【2026】GraphQL APIをClaude Codeで作る実践ガイド

GraphQL APIをClaude Codeで開発する実践ガイド。スキーマ設計からresolver・DataLoader・N+1回避・認可・クエリ深さ制限・テストまで、指示例とコード例つきで2026年6月時点の公式準拠で解説。

【2026】GraphQL APIをClaude Codeで作る実践ガイド

結論:GraphQL開発は「スキーマを正本にしてClaude Codeに実装させる」と速い

GraphQL APIをClaude Codeで作るときの肝は、いきなりresolverを書かせないことです。先にschema.graphqlという「正本(Source of Truth)」を固め、そこからtype・query・mutation・resolverを生成させる。この順番にするだけで、生成コードの手戻りが目に見えて減ります。本記事は2026年6月時点のClaude Code公式ドキュメントとGraphQL公式(graphql.org)の推奨に沿って、設計から実装・テスト・運用までの実践手順を、指示例とコード例つきでまとめました。

  • 結論:スキーマ駆動(schema-first)でClaude Codeを動かすと、REST的な「エンドポイント乱立」を避けつつ型安全に実装できる。
  • 要点3つ:①CLAUDE.mdにGraphQL規約を書く ②スキーマ→resolverの順で生成させる ③N+1・クエリ深さ・認可は人が必ずレビューする。
  • 対象読者:GraphQLサーバー(Apollo Server / GraphQL Yoga 等)を実装・運用するバックエンドエンジニア、PM、Claude Code導入検討者。
  • 今日やること:手元のプロジェクトに最小スキーマを置き、Claude Codeに「このスキーマからresolverの雛形を作って」と頼んでみる。
GraphQL APIをClaude Codeで作る6領域。①スキーマ設計(型・クエリの整理)②既存コードの把握 ③resolver実装(DataLoader・N+1回避)④認可・クエリ深さ/複雑度の制限 ⑤テストと動作確認 ⑥ドキュメント化。生成コードを鵜呑みにしない・人がレビュー、入力検証・認可などセキュリティに注意(OWASP)。
GraphQL APIをClaude Codeで作る6領域(スキーマ設計・既存把握・resolver実装・認可制限・テスト・ドキュメント化)

正直に言うと、最初にやらかしたのは「GraphQLサーバー作って」だけ投げて、いきなり完成形を吐かせようとしたパターンでした。返ってきたのはそれっぽいコードなんですが、スキーマと実装がじわじわズレていて、後からフィールドを足すたびに整合が崩れる。GraphQLは「型システムそのものが契約」なので、契約(スキーマ)を先に固定する。この一点を押さえると、Claude Codeの生成精度が一段上がります。

① 設計:スキーマファーストでtype・query・mutationを整理する

GraphQL公式(graphql.org/learn)でも、APIは「クライアントが必要なデータの形」を起点に設計するのが基本です。RESTのようにエンドポイントを並べるのではなく、1つのエンドポイントに対してスキーマで表現する。まずは扱うドメイン(例:ブログのPostとUser)を型として書き出します。

Claude Codeへの指示はこう出しました。

あなたはGraphQLのスキーマ設計者です。次の要件からschema.graphqlを書いてください。
- Post(id, title, body, published, author, createdAt)
- User(id, name, email, posts)
- Query: posts(published: Boolean), post(id: ID!), user(id: ID!)
- Mutation: createPost(input: CreatePostInput!), publishPost(id: ID!)
制約:
- ID は ID! 型、必須フィールドは非null(!)で表現
- ページネーション余地を残すが今回は未実装でよい(コメントで明記)
- input は専用の input type に分離する

出てきたスキーマはこんな形です。生成された内容は必ず目で追って、必須/任意(!の有無)が意図通りか確認します。

type Post {
  id: ID!
  title: String!
  body: String!
  published: Boolean!
  author: User!
  createdAt: String!
}

type User {
  id: ID!
  name: String!
  email: String!
  posts: [Post!]!
}

input CreatePostInput {
  title: String!
  body: String!
  authorId: ID!
}

type Query {
  posts(published: Boolean): [Post!]!
  post(id: ID!): Post
  user(id: ID!): User
}

type Mutation {
  createPost(input: CreatePostInput!): Post!
  publishPost(id: ID!): Post!
}

ここで決めておくと後がラクなのが「nullの扱い」です。GraphQLでは非nullフィールド(!)の解決が失敗すると、エラーが親フィールドまで伝播します。author を User! にした以上、authorが必ず取れる前提を満たすコードが要る——この設計判断は人がやるべきところです。

② 既存コードの把握:CLAUDE.mdにGraphQL規約を書いてから読ませる

Claude CodeはプロジェクトルートやサブディレクトリのCLAUDE.mdをメモリとして読み込みます(公式: Claude Code memory)。GraphQL案件では、ここに「うちのGraphQL規約」を書いておくと、生成コードが一気に自分たちのスタイルに寄ります。

実際に置いているCLAUDE.mdの抜粋です。

# GraphQL 実装規約

- サーバー: Apollo Server v4(@apollo/server)
- スキーマは schema.graphql を正本とし、resolver は src/resolvers/ に型ごとに分割
- DataLoader を使い N+1 を必ず回避する(User.posts, Post.author など関連解決は batch 化)
- 認可は resolver の最上段で context.user を検証してから実行
- エラーは GraphQLError + extensions.code(UNAUTHENTICATED / FORBIDDEN / BAD_USER_INPUT)で返す
- 入力検証は zod で input ごとに行う

既存リポジトリに後から入る場合は、いきなり書き換えさせず「現状把握」から頼むのが安全です。

このリポジトリのGraphQL構成を調査して、次を箇条書きで報告してください。
1. スキーマ定義の場所と分割方針(SDL or code-first か)
2. resolver の登録方法と DataLoader の有無
3. 認証・認可がどこで効いているか
4. N+1 が起きていそうな関連フィールド
まだコードは変更しないでください。

「まだ変更しないで」を付けるのが地味に効きます。調査と実装を分けると、こちらが構成を理解しないまま大改修される事故を防げます。

③ 実装:resolver・DataLoader・エラーハンドリングを規約に沿わせる

スキーマとCLAUDE.mdが揃ったら、resolver実装に入ります。GraphQLで最初にハマるのが N+1問題です。postsを10件取ったあと、各PostのauthorをそれぞれDBに問い合わせると11回クエリが飛ぶ。これはDataLoaderでバッチ化するのが定石です。

指示と、生成させたDataLoaderの例です(Apollo Server v4 + DataLoader想定)。

// 指示:
// User.posts と Post.author の N+1 を DataLoader で解消して。
// context にローダーを差し込み、各 resolver はローダー経由で関連を取得する形にして。

import DataLoader from "dataloader";

export function createLoaders(db) {
  return {
    userById: new DataLoader(async (ids) => {
      const rows = await db.user.findMany({ where: { id: { in: ids } } });
      const map = new Map(rows.map((u) => [u.id, u]));
      return ids.map((id) => map.get(id) ?? null);
    }),
    postsByAuthorId: new DataLoader(async (authorIds) => {
      const rows = await db.post.findMany({
        where: { authorId: { in: authorIds } },
      });
      return authorIds.map((aid) =>
        rows.filter((p) => p.authorId === aid)
      );
    }),
  };
}

resolver側はローダーを呼ぶだけにします。エラーは「文字列をthrow」ではなく、コード付きのGraphQLErrorで返すよう統一させます。

import { GraphQLError } from "graphql";

export const resolvers = {
  Query: {
    post: async (_p, { id }, ctx) => {
      const post = await ctx.db.post.findUnique({ where: { id } });
      if (!post) {
        throw new GraphQLError("Post not found", {
          extensions: { code: "NOT_FOUND" },
        });
      }
      return post;
    },
  },
  Post: {
    // N+1 を避けるため author は loader 経由
    author: (post, _a, ctx) => ctx.loaders.userById.load(post.authorId),
  },
  User: {
    posts: (user, _a, ctx) => ctx.loaders.postsByAuthorId.load(user.id),
  },
  Mutation: {
    createPost: async (_p, { input }, ctx) => {
      if (!ctx.user) {
        throw new GraphQLError("Login required", {
          extensions: { code: "UNAUTHENTICATED" },
        });
      }
      // 入力検証はここで(次節)
      return ctx.db.post.create({ data: { ...input, published: false } });
    },
  },
};

認可(ctx.userのチェック)と入力検証は、Claude Codeが省略しがちな箇所です。生成直後に必ず「全mutationの先頭で認可しているか」を自分の目で確認してください。

実装の進め方(おすすめ順)

  1. schema.graphql を確定させる(型と必須/任意を人が決める)。
  2. CLAUDE.md にGraphQL規約を追記し、Claude Codeに読ませる。
  3. resolverの「雛形だけ」を生成させ、DB接続はモックで通す。
  4. DataLoaderを導入し、関連フィールド(author・posts等)をバッチ化する。
  5. 認可・入力検証・エラーコードを各resolverに差し込む。
  6. テストを生成して挙動を固定し、最後にクエリ深さ・複雑度の上限を入れる。

④ 入力検証とセキュリティ:ここは生成を鵜呑みにしない

GraphQLは1エンドポイントで柔軟にクエリできる反面、攻撃面も独特です。OWASPのGraphQL Cheat Sheetでも、クエリ深さ制限・複雑度制限・introspectionの本番制御・入力検証が推奨されています。Claude Codeに任せきりにせず、次を明示的に依頼します。

入力検証はzod等でinput typeごとに行わせます。

import { z } from "zod";

const CreatePostSchema = z.object({
  title: z.string().min(1).max(200),
  body: z.string().min(1).max(50000),
  authorId: z.string().uuid(),
});

// resolver 内
const parsed = CreatePostSchema.safeParse(input);
if (!parsed.success) {
  throw new GraphQLError("Invalid input", {
    extensions: { code: "BAD_USER_INPUT", issues: parsed.error.issues },
  });
}

悪意あるネストクエリ(深い再帰で負荷をかける攻撃)対策として、深さ・複雑度の上限も入れます。

あなたはGraphQLのセキュリティ担当です。次を実装してください。
- クエリの最大深さを 7 に制限(depth limit)
- クエリ複雑度の上限を設け、超過時は実行前に拒否
- 本番環境では introspection を無効化(開発のみ有効)
- レート制限の方針をコメントで提案
OWASP GraphQL Cheat Sheet の推奨に沿うこと。

ただし——ここが本記事で一番伝えたいところですが、生成された上限値(深さ7・複雑度の閾値)は、あなたのスキーマに対して妥当とは限りません。正当なクエリが弾かれないか、必ず実トラフィックで検証してください。認証・認可・入力検証は、AIが「それっぽく」書けてしまうぶん、人のレビューが最後の砦です。

⑤ テストと動作確認:クエリ単位で挙動を固定する

GraphQLのテストは「実際に投げるクエリ文字列」を使って書くと安定します。Claude Codeにテストを生成させるときも、クエリ例を渡すと精度が上がります。

次のresolverのテストを Vitest で書いてください。
- query { post(id: "存在しないID") } → errors に code NOT_FOUND
- mutation createPost を未ログインで実行 → code UNAUTHENTICATED
- User.posts が N+1 にならない(loader が1回だけ呼ばれる)ことを spy で検証
DBはインメモリのモックを使い、ネットワークには出ないこと。

動作確認の手順は次の通りです。

  1. 開発サーバーを起動し、GraphQL Playground / Apollo Sandbox でスキーマがロードされるか見る。
  2. 正常系クエリ(posts取得)を投げ、想定の型で返るか確認する。
  3. 異常系(不正ID・未認証mutation)を投げ、extensions.codeが期待通りか確認する。
  4. 関連フィールドを含むクエリを投げ、DBログでクエリ回数が増殖していないか(N+1が消えているか)を見る。
  5. 深いネストクエリを投げ、depth limitが効くか確認する。

「テストが通った」で安心せず、生成されたモックが本物のDB挙動と乖離していないかは別途見ます。AIのテストは「自分が書いた実装に都合よく緑になる」ことがあるので、最低1本は手で書いたテストを混ぜると安心です。

⑥ ドキュメント化:スキーマから仕様を生成して落差を埋める

GraphQLはスキーマ自体がドキュメントですが、フロント担当やレビュアー向けに人間可読な説明があると親切です。Claude Codeにスキーマを読ませて、フィールドの意味・代表的なクエリ例・エラーコード一覧をMarkdownで出させます。

schema.graphql を読んで docs/graphql.md を生成してください。
- 各 type / query / mutation の用途を1行説明
- 代表的なクエリ・mutationの実例(変数つき)
- extensions.code の一覧と発生条件
- 認可が必要な操作に🔒マークを付ける
スキーマに無いフィールドは書かないこと(憶測禁止)。

「スキーマに無いものは書くな」を必ず添えます。これを付けないと、実装していないページネーション引数などを“ある前提”で書いてしまうことがあります。生成後はスキーマと突き合わせて、嘘がないかをこちらで確認します。

⑦ よくある失敗パターンと回避策

実際に踏んだ落とし穴を、❌と⭕で並べます。

  • 「GraphQLサーバー作って」だけ投げる → スキーマと実装が乖離。⭕ 先にschema.graphqlを確定させ、そこからresolverを生成させる。
  • 関連フィールドを素直にDB問い合わせ → N+1で本番が詰まる。⭕ DataLoaderでバッチ化する規約をCLAUDE.mdに明記。
  • 認可をresolverごとに書き忘れる → 未ログインでもmutationが通る。⭕ 全mutation先頭のctx.user検証を人がレビューで担保。
  • introspectionを本番で開けっ放し → スキーマ構造が丸見え。⭕ 本番は無効化し、開発のみ有効にする(OWASP推奨)。
  • 深さ・複雑度の上限をAIの初期値のまま採用 → 正当なクエリが弾かれる/弾けない。⭕ 実トラフィックで閾値を調整する。

段階的に導入するロードマップ

  1. 第1週:最小スキーマ(Post/User)でClaude Codeにresolver雛形を作らせ、流れを体感する。
  2. 第2週:CLAUDE.mdにGraphQL規約を整備し、DataLoaderとエラーコードを標準化する。
  3. 第3週:認可・入力検証・depth/complexity制限を入れ、テストで固定する。
  4. 第4週:既存RESTからの段階移行や、スキーマからのドキュメント自動生成まで広げる。

よくある質問(FAQ)

Q. Claude CodeはGraphQL専用の機能を持っていますか?
A. いいえ。Claude Codeは汎用のコーディングエージェントで、GraphQL専用コマンドはありません(2026年6月時点・公式ドキュメント基準)。スキーマやCLAUDE.mdといった「文脈」を与えることで、GraphQL実装に最適化します。

Q. schema-firstとcode-first、どちらがClaude Codeと相性がいいですか?
A. どちらでも動きますが、スキーマを正本にできるschema-firstの方が、生成と実装のズレを検知しやすく、レビューがラクです。

Q. 生成されたresolverをそのまま本番に出していい?
A. ダメです。特に認可・入力検証・N+1・クエリ制限は人が必ずレビューしてください。AIは「動くが安全でない」コードを自然に書きます。

まとめ:今日から始める3つのアクション

  1. 手元のプロジェクトに最小のschema.graphqlを置き、Claude Codeに「このスキーマからresolver雛形を作って」と頼む。
  2. CLAUDE.mdにGraphQL規約(DataLoader必須・エラーコード・認可方針)を1ページ書く。
  3. 生成コードのうち「認可・入力検証・クエリ深さ制限」の3点を、自分の目でレビューする習慣にする。

次回は、このGraphQLサーバーに認証を載せる実装(トークン検証・context注入)を、Claude Codeでどう進めるかを掘り下げます。

あわせて読みたい

著者プロフィール

佐藤傑(さとう・すぐる)。株式会社Uravation代表取締役。X(@SuguruKun_ai)フォロワー約10万人。100社以上の企業向けAI研修・導入支援に携わる。著書『AIエージェント仕事術』(SBクリエイティブ)。

参考・出典

Next Step

この事例を、自社の業務に置き換える。

対象業務、利用データ、評価基準、社内展開の順番まで整理すると、Claude Code導入の失敗を減らせます。

導入を相談する