読み込み中...
GraphQLは、Facebookが開発したAPIクエリ言語です。RESTful APIの課題を解決し、より効率的なデータ取得を実現します。この記事では、GraphQLの基本から実践的な使い方まで解説します。
定義: APIのためのクエリ言語とランタイム
Over-fetching(過剰取得):
// ユーザー名だけ欲しいのに全データ取得
GET /users/1
{
"id": 1,
"name": "田中太郎",
"email": "tanaka@example.com",
"address": "...",
"phone": "...",
...
}Under-fetching(不足取得):
// 複数回リクエストが必要
GET /users/1
GET /users/1/posts
GET /users/1/comments必要なデータだけ取得:
query {
user(id: 1) {
name
posts {
title
}
}
}レスポンス:
{
"data": {
"user": {
"name": "田中太郎",
"posts": [
{ "title": "GraphQL入門" }
]
}
}
}query GetUser {
user(id: "1") {
id
name
email
posts {
title
createdAt
}
}
}mutation CreatePost {
createPost(input: {
title: "新しい記事"
content: "内容..."
}) {
id
title
createdAt
}
}subscription OnPostCreated {
postCreated {
id
title
author {
name
}
}
}type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
createdAt: DateTime!
}
type Query {
user(id: ID!): User
users: [User!]!
post(id: ID!): Post
posts: [Post!]!
}
type Mutation {
createUser(input: CreateUserInput!): User!
createPost(input: CreatePostInput!): Post!
updatePost(id: ID!, input: UpdatePostInput!): Post!
deletePost(id: ID!): Boolean!
}String: 文字列Int: 整数Float: 浮動小数点数Boolean: 真偽値ID: 一意識別子!: 必須(null不可)[]: 配列const { ApolloServer, gql } = require('apollo-server');
// スキーマ定義
const typeDefs = gql`
type User {
id: ID!
name: String!
email: String!
}
type Query {
user(id: ID!): User
users: [User!]!
}
`;
// リゾルバー
const resolvers = {
Query: {
user: (parent, { id }, context) => {
return context.dataSources.userAPI.getUser(id);
},
users: (parent, args, context) => {
return context.dataSources.userAPI.getUsers();
},
},
};
// サーバー起動
const server = new ApolloServer({
typeDefs,
resolvers,
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});import { ApolloClient, InMemoryCache, gql, useQuery } from '@apollo/client';
// クライアント設定
const client = new ApolloClient({
uri: 'http://localhost:4000/graphql',
cache: new InMemoryCache(),
});
// クエリ定義
const GET_USER = gql`
query GetUser($id: ID!) {
user(id: $id) {
name
email
posts {
title
}
}
}
`;
// コンポーネント
function UserProfile({ userId }) {
const { loading, error, data } = useQuery(GET_USER, {
variables: { id: userId },
});
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
<h1>{data.user.name}</h1>
<p>{data.user.email}</p>
<h2>Posts</h2>
{data.user.posts.map(post => (
<div key={post.title}>{post.title}</div>
))}
</div>
);
}User, Post)firstName, createdAt)type Query {
posts(
first: Int
after: String
last: Int
before: String
): PostConnection!
}
type PostConnection {
edges: [PostEdge!]!
pageInfo: PageInfo!
}
type PostEdge {
node: Post!
cursor: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}const resolvers = {
Query: {
user: async (parent, { id }, context) => {
try {
const user = await context.dataSources.userAPI.getUser(id);
if (!user) {
throw new Error('User not found');
}
return user;
} catch (error) {
throw new Error(`Failed to fetch user: ${error.message}`);
}
},
},
};const DataLoader = require('dataloader');
const userLoader = new DataLoader(async (userIds) => {
const users = await Users.findAll({
where: { id: userIds }
});
return userIds.map(id => users.find(user => user.id === id));
});
const resolvers = {
Post: {
author: (post, args, { userLoader }) => {
return userLoader.load(post.authorId);
},
},
};const depthLimit = require('graphql-depth-limit');
const server = new ApolloServer({
typeDefs,
resolvers,
validationRules: [depthLimit(5)],
});const { createComplexityLimitRule } = require('graphql-validation-complexity');
const server = new ApolloServer({
typeDefs,
resolvers,
validationRules: [
createComplexityLimitRule(1000),
],
});const resolvers = {
Query: {
me: (parent, args, context) => {
if (!context.user) {
throw new AuthenticationError('Not authenticated');
}
return context.user;
},
},
Mutation: {
deletePost: (parent, { id }, context) => {
if (!context.user) {
throw new AuthenticationError('Not authenticated');
}
const post = getPost(id);
if (post.authorId !== context.user.id) {
throw new ForbiddenError('Not authorized');
}
return deletePost(id);
},
},
};GraphQLは、RESTの課題を解決する強力なAPIクエリ言語です。
メリット:
デメリット:
おすすめのケース:
まずは小さなプロジェクトから始めて、GraphQLの恩恵を実感してみてください。
次に読むべき記事:
コメント