GraphQL入門:REST APIとの違いと使いどころを実例で理解する
目次
GraphQLとは
GraphQLはFacebookが2015年にオープンソース化したAPIのクエリ言語です。REST APIと異なり、クライアントが「どのデータを取得したいか」を自分で指定できます。
GraphQLはサーバーサイドで動くランタイムとクエリ言語の両方を指します。Apollo Server・Yoga・Pothos等のライブラリを使ってNode.js上でGraphQLサーバーを構築するのが一般的です。
RESTとGraphQLの根本的な違い
REST APIには2つの構造的な問題があります。
問題1: オーバーフェッチ(Over-fetching)
必要なデータ以上のデータが返ってくる問題です。
GET /users/1
{
"id": 1,
"name": "田中太郎",
"email": "tanaka@example.com",
"age": 28,
"address": "東京都渋谷区...",
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2026-01-10T08:00:00Z",
"preferences": { ... },
"statistics": { ... }
}
画面に表示したいのはnameだけなのに、全フィールドが返ってきます。モバイルアプリでは通信量の無駄遣いになります。
問題2: アンダーフェッチ(Under-fetching)
必要なデータを1回のリクエストで取得できず、複数回リクエストが必要になる問題です。
GET /users/1 # ユーザー情報取得
GET /users/1/posts # そのユーザーの投稿一覧取得
GET /posts/42/comments # 特定投稿のコメント取得
3回のHTTPリクエストが必要になり、ウォーターフォール問題が発生します。
GraphQLで解決する
GraphQLでは1回のリクエストで必要なデータだけを取得できます。
query {
user(id: "1") {
name
posts {
title
comments {
body
}
}
}
}
このクエリを1つのHTTPリクエスト(POST /graphql)で送るだけで、ネストした全データが返ってきます。
GraphQLの基本概念
スキーマ定義(SDL)
GraphQLはスキーマファーストで開発します。どんなデータを返せるかをSDL(Schema Definition Language)で定義します。
# 型定義
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
createdAt: String!
}
type Post {
id: ID!
title: String!
body: String!
author: User!
comments: [Comment!]!
publishedAt: String
}
type Comment {
id: ID!
body: String!
author: User!
}
# クエリ(読み取り)
type Query {
user(id: ID!): User
users: [User!]!
post(id: ID!): Post
}
# ミューテーション(書き込み)
type Mutation {
createPost(title: String!, body: String!, authorId: ID!): Post!
updatePost(id: ID!, title: String, body: String): Post!
deletePost(id: ID!): Boolean!
}
# サブスクリプション(リアルタイム)
type Subscription {
commentAdded(postId: ID!): Comment!
}
!は非null(値が必ず存在する)を表します。[Post!]!は「Postの非null配列、かつ配列自体も非null」です。
Query — データの読み取り
# 基本的なクエリ
query GetUser {
user(id: "1") {
id
name
email
}
}
# フラグメントで共通フィールドを再利用
fragment UserFields on User {
id
name
email
}
query GetUsers {
users {
...UserFields
posts {
title
}
}
}
# 変数を使う(ハードコードを避ける)
query GetUser($userId: ID!) {
user(id: $userId) {
...UserFields
}
}
変数はリクエスト時に別途JSONで渡します。
{
"userId": "42"
}
Mutation — データの書き込み
mutation CreatePost($title: String!, $body: String!, $authorId: ID!) {
createPost(title: $title, body: $body, authorId: $authorId) {
id
title
publishedAt
author {
name
}
}
}
MutationもQueryと同様に必要なフィールドだけを指定して返却データを絞り込めます。
Subscription — リアルタイムデータ
WebSocketを使ってリアルタイムにデータを受信します。チャットアプリや通知機能に活用されます。
subscription OnCommentAdded($postId: ID!) {
commentAdded(postId: $postId) {
id
body
author {
name
}
}
}
GitHub GraphQL APIを使った実践例
GitHubはGraphQL APIを公開しており、無料で試せます。GitHub GraphQL Explorerから直接クエリを実行できます。
# 自分のリポジトリ一覧と各リポジトリのStar数を取得
query {
viewer {
login
name
repositories(first: 10, orderBy: { field: STARGAZERS, direction: DESC }) {
nodes {
name
description
stargazerCount
primaryLanguage {
name
}
updatedAt
}
}
}
}
# curl でリクエスト
curl -H "Authorization: Bearer YOUR_GITHUB_TOKEN" \
-H "Content-Type: application/json" \
-X POST \
-d '{"query": "{ viewer { login } }"}' \
https://api.github.com/graphql
Apollo Clientの基本使い方
フロントエンドでGraphQLを扱うにはApollo Clientが最もポピュラーなライブラリです。
npm install @apollo/client graphql
クライアントの初期化
// src/lib/apolloClient.ts
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'
const httpLink = createHttpLink({
uri: 'https://api.example.com/graphql',
headers: {
authorization: `Bearer ${localStorage.getItem('token')}`,
},
})
export const client = new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
})
React + Apollo Clientの使い方
import { useQuery, useMutation, gql } from '@apollo/client'
const GET_USERS = gql`
query GetUsers {
users {
id
name
email
}
}
`
const CREATE_USER = gql`
mutation CreateUser($name: String!, $email: String!) {
createUser(name: $name, email: $email) {
id
name
}
}
`
function UserList() {
// Query フック
const { loading, error, data } = useQuery(GET_USERS)
// Mutation フック
const [createUser] = useMutation(CREATE_USER, {
// キャッシュを自動更新
refetchQueries: [{ query: GET_USERS }],
})
if (loading) return <p>読み込み中...</p>
if (error) return <p>エラー: {error.message}</p>
return (
<div>
<ul>
{data.users.map((user: { id: string; name: string }) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
<button onClick={() => createUser({ variables: { name: '新規ユーザー', email: 'new@example.com' } })}>
ユーザー追加
</button>
</div>
)
}
GraphQLの向き・不向き
GraphQLが特に向いているシナリオと、そうでないシナリオを整理します。
GraphQLが向いている場合
- 複数のクライアントが同じAPIを利用する場合(iOS / Android / Web):各クライアントが必要なフィールドだけ取得できる
- ネストしたデータを頻繁に取得する場合:ユーザー→投稿→コメントのような階層データ
- 開発速度を重視するとき:フロントエンドがAPIの仕様変更を気にせず開発できる
RESTの方が向いている場合
- シンプルなCRUD操作のみの場合:GraphQLのオーバーヘッドが不要
- ファイルアップロード:GraphQLはバイナリデータの扱いが複雑
- HTTP キャッシュを活用したい場合:GraphQLはPOST中心のためCDNキャッシュが効きにくい
- チームがRESTに慣れている場合:学習コストを考慮する
初めてのGraphQL ―Webサービスを作って学ぶAPI設計
GraphQLの設計思想からApollo Server/Clientの実装まで丁寧に解説。実際にアプリを作りながらGraphQLのエコシステム全体を学べる実践的な一冊です。
※ アフィリエイトリンクを含みます
まとめ
GraphQLはREST APIの「オーバーフェッチ・アンダーフェッチ問題」を解決するために設計されています。
- Query: データの読み取り(必要なフィールドだけ指定)
- Mutation: データの書き込み・更新・削除
- Subscription: WebSocketによるリアルタイム受信
- スキーマ: SDL で型定義を先に書くスキーマファースト開発
- Apollo Client:
useQuery/useMutationでReact統合が簡単
まずはGitHub GraphQL APIを使って実際にクエリを書いてみましょう。次のステップとして、Apollo ServerかGraphQL Yogaでローカルにサーバーを立て、独自スキーマを定義してみると理解が深まります。