TechBlog

GraphQL入門:REST APIとの違いと使いどころを実例で理解する

by あくえり
#GraphQL #API #REST #フロントエンド #バックエンド
GraphQL入門ガイド
目次

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でローカルにサーバーを立て、独自スキーマを定義してみると理解が深まります。

共有: