Communitygithub.com

GraphQL Yoga パターン

GraphQL Yoga v5サーバーのセットアップ、Envelopプラグイン、サブスクリプション、エラーマスキングに関する包括的なスキルです。

GraphQL Yoga パターン とは?

このスキルは、Fetch API互換のGraphQLサーバー「GraphQL Yoga v5」を使いこなすための包括的なガイドです。`createYoga`と`createSchema`を用いたサーバーセットアップ、Envelopプラグインシステムによる機能拡張、SSE(デフォルト)やWebSocketを用いたサブスクリプション、意図的なエラーと予期せぬエラーを区別するエラーマスキングなど、実運用に即したパターンを提供します。Node.js、Bun、Deno、Cloudflare Workersなど、あらゆるJavaScriptランタイムで同一のコードが動作するのが最大の利点であり、特にYoga固有のプラグインを優先することでHTTPレイヤーでの処理最適化(キャッシュによるパース・バリデーションのスキップなど)が可能です。また、スキーマ定義はSDLファースト、コードファースト(Pothosなど)、バニラgraphql-jsのいずれにも対応しており、プロジェクトの要件に合わせて柔軟に選択できます。

対応✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/agents-inc/skills/tree/HEAD/src/skills/api-graphql-yoga

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

GraphQL Yoga パターン は何をしますか?

クイックガイド: createYoga + createSchema を使用して、あらゆるJSランタイムで動作するFetch API互換のGraphQLサーバーを構築します。Yoga v5はEnvelopを使用したプラグイン構成、SSEによるデフォルトのサブスクリプション、組み込みのエラーマスキング、CORSを標準で提供します。クライアント向けの意図的なエラーは、graphql-yoga ではなく graphql から GraphQLError をインポートしてスローします。HTTPレベルの最適化には、Envelop相当のプラグインよりもYoga固有のプラグインを優先します。


<critical_requirements>

重要: このスキルを使用する前に

すべてのコードは CLAUDE.md のプロジェクト規約に従うこと(ケバブケース、名前付きエクスポート、インポート順序、import type、名前付き定数)

(GraphQLError は 'graphql' からインポートすること。'graphql-yoga' からはインポートしないでください。これは標準の graphql-js エクスポートです)

(Envelop相当のプラグインよりもYoga固有のプラグインを優先すること。YogaプラグインはHTTPレイヤーで動作し、キャッシュ/永続化された結果のためにGraphQLの実行を完全にスキップできます)

(スキーマファーストの場合は 'graphql-yoga' の createSchema を使用すること。v5では createYoga に直接 typeDefs/resolvers オブジェクトを渡すことはサポートされていません)

(すべての数値には名前付き定数を使用すること。タイムアウト、TTL、ポート番号、制限値など)

</critical_requirements>


自動検出: GraphQL Yoga、graphql-yoga、createYoga、createSchema、createPubSub、Envelop、useResponseCache、useCSRFPrevention、usePersistedOperations、GraphQL サブスクリプション SSE、エラーマスキング、maskedErrors、graphql-ws、Yoga プラグインフック、onRequest、onParams

使用すべきケース:

  • Node.js、Bun、Deno、Cloudflare Workers で動作するGraphQLサーバーを構築する場合
  • SSE(デフォルト)またはWebSocketを介したサブスクリプションが必要なAPI
  • Envelopプラグイン(キャッシュ、認証、ログ記録)でGraphQL実行を拡張する場合
  • GraphQL Multipart Request仕様を使用したファイルアップロード
  • エラーマスキング、CORS、CSRF保護が必要な本番API

使用すべきでないケース:

  • GraphQLを必要としないREST専用API
  • フレームワークの組み込みルートハンドラで十分な単純なCRUD
  • フェデレーションゲートウェイが必要な場合(専用ゲートウェイソリューションを検討)

カバーする主要パターン:

  • createYoga と createSchema を使用したサーバーセットアップ(スキーマファースト)
  • createYoga<ServerContext> のジェネリクスによる型安全なコンテキスト
  • Envelopプラグインシステム: ライフサイクルフック、カスタムプラグイン、Yoga固有のプラグイン
  • サブスクリプション: SSE(デフォルト)、graphql-ws によるWebSocket、組み込みPubSub
  • エラーマスキングと意図的な GraphQLError の公開
  • WHATWG File スカラーを使用したファイルアップロード
  • 本番運用の強化: CORS、CSRF防止、GraphQL Armor、ログ記録
  • クロスランタイムデプロイ: Node.js、Bun、Deno、Cloudflare Workers

詳細リソース:

  • examples/core.md - サーバーセットアップ、スキーマ、コンテキスト、リゾルバー、クロスランタイムデプロイ
  • examples/plugins.md - Envelopプラグイン、カスタムプラグイン、ライフサイクルフック
  • examples/subscriptions.md - SSE、WebSocket、PubSub、フィルタリング
  • examples/error-handling.md - エラーマスキング、GraphQLError、カスタムマスキング
  • examples/production.md - CORS、CSRF、レスポンスキャッシュ、永続化操作、ログ記録
  • reference.md - 決定フレームワーク、プラグインリファレンス、本番チェックリスト

哲学

GraphQL Yogaは、何でも含まれている、Fetch API互換のGraphQLサーバーです。そのコアはWHATWG Fetch API(Request/Response)に基づいており、ランタイムに依存しません。つまり、同じサーバーコードをNode.js、Bun、Deno、そしてエッジランタイムにデプロイできます。Envelopプラグインシステムは、HTTPレイヤーとGraphQL実行レイヤーの両方で合成可能なミドルウェアを提供します。

スキーマアプローチ: Yogaはスキーマライブラリに依存しません。createSchema(スキーマファーストSDL)、Pothos(コードファースト)、またはバニラの graphql-js など、GraphQLSchema を生成するものなら何でも動作します。

プラグインの優先順位: 同じ機能(キャッシュ、永続化操作、defer/stream)に対してEnvelopプラグインとYoga固有のプラグインの両方が存在する場合は、常にYogaバリアントを選択します。YogaプラグインはHTTPレイヤーにフックし、キャッシュまたは永続化された結果の場合、GraphQL実行が開始される前にショートサーキットして、パースとバリデーションを完全にスキップできます。

エラーに関する哲学: 本番環境では、すべての予期しないエラーはデフォルトでマスクされます。意図的なエラーは graphql パッケージから GraphQLError としてスローされます。これらはマスキングをバイパスし、メッセージと拡張機能をそのままクライアントに到達させます。


コアパターン

パターン 1: createYoga によるサーバーセットアップ

SDLベースのスキーマには createSchema を使用してYogaインスタンスを作成します。yogaインスタンスはFetch APIハンドラそのものです。任意のランタイムのHTTPサーバーに直接渡します。

import { createYoga, createSchema } from "graphql-yoga";
import { createServer } from "node:http";

const PORT = 4000;

const yoga = createYoga({
  schema: createSchema({
    typeDefs: /* GraphQL */ `
      type Query {
        greeting(name: String!): String!
      }
    `,
    resolvers: {
      Query: {
        greeting: (_, { name }) => `Hello, ${name}!`,
      },
    },
  }),
});

const server = createServer(yoga);
server.listen(PORT, () => {
  console.info(`Server running on http://localhost:${PORT}/graphql`);
});

良い理由: createSchema は makeExecutableSchema をラップし、yogaインスタンスは標準のFetchハンドラであり、任意のランタイムで動作します

完全なセットアップ、クロスランタイムデプロイ、型安全なコンテキストについては、examples/core.md を参照してください。


パターン 2: 型安全なコンテキスト

サーバー固有のコンテキストタイピングのために createYoga にジェネリックを渡します。context ファクトリは YogaInitialContext(request と params を含む)を受け取り、カスタムコンテキストを返します。

import { createYoga, type YogaInitialContext } from "graphql-yoga";

interface ServerContext {
  req: IncomingMessage;
  res: ServerResponse;
}

const yoga = createYoga<ServerContext>({
  schema,
  context: async ({ request }: YogaInitialContext) => {
    const token = request.headers.get("authorization");
    return { user: token ? await verifyToken(token) : null };
  },
});

良い理由: ジェネリック型はリゾルバーのコンテキストパラメーターに伝播し、request は標準のFetch APIを使用します(フレームワーク固有の req/res ではありません)

完全なコンテキストパターンについては、examples/core.md を参照してください。


パターン 3: Envelop プラグインシステム

プラグインは plugins 配列で渡します。利用可能な場合はYoga固有のプラグインを使用します。これらはHTTPレイヤーで動作し、GraphQL実行を完全にスキップできます。

import { createYoga } from "graphql-yoga";
import { useResponseCache } from "@graphql-yoga/plugin-response-cache";

const CACHE_TTL_MS = 2_000;

const yoga = createYoga({
  schema,
  plugins: [
    useResponseCache({
      session: () => null,
      ttl: CACHE_TTL_MS,
    }),
  ],
});

良い理由: Yogaのレスポンスキャッシュは、キャッシュされた結果に対してパース/バリデーションをスキップします(Envelop相当のものはできません)。プラグインは競合なく構成できます。

カスタムプラグイン、ライフサイクルフック、およびすべてのYoga固有プラグインについては、examples/plugins.md を参照してください。


パターン 4: SSE を使用したサブスクリプション(デフォルト)

YogaはデフォルトでサブスクリプションにServer-Sent Eventsを使用します。WebSocketのセットアップは不要です。サブスクリプションリゾルバーでは AsyncGenerator 構文を使用します。

const schema = createSchema({
  typeDefs: /* GraphQL */ `
    type Subscription {
      countdown(from: Int!): Int!
    }
  `,
  resolvers: {
    Subscription: {
      countdown: {
        subscribe: async function* (_, { from }) {
          for (let i = from; i >= 0; i--) {
            await new Promise((resolve) => setTimeout(resolve, 1_000));
            yield { countdown: i };
          }
        },
      },
    },
  },
});

良い理由: WebSocketインフラが不要で、HTTPプロキシやロードバランサーを介して動作し、クライアント向けには graphql-sse ライブラリが利用可能です

PubSub、WebSocketセットアップ、フィルタリングについては、examples/subscriptions.md を参照してください。


パターン 5: エラーマスキングと GraphQLError

Yogaはデフォルトですべての予期しないエラーをマスクします。クライアント向けの意図的なエラーには、graphql から GraphQLError をスローします。これらはマスキングをバイパスします。

import { GraphQLError } from "graphql";

const NOT_FOUND_CODE = "USER_NOT_FOUND";

throw new GraphQLError("User not found", {
  extensions: { code: NOT_FOUND_CODE },
});

良い理由: 予期しないエラーが内部情報(データベースの詳細、スタックトレース)を漏洩することはなく、意図的なエラーはメッセージと拡張機能とともに通過します

カスタムマスキング、マスキングの無効化、開発モードについては、examples/error-handling.md を参照してください。


パターン 6: ファイルアップロード

YogaはGraphQL Multipart Request仕様をサポートしています。File スカラーを追加し、リゾルバーでWHATWG File オブジェクトを受け取ります。

const schema = createSchema({
  typeDefs: /* GraphQL */ `
    scalar File
    type Mutation {
      uploadFile(file: File!): Boolean!
    }
  `,
  resolvers: {
    Mutation: {
      uploadFile: async (_, { file }: { file: File }) => {
        const content = await file.arrayBuffer();
        // ファイル内容を処理
        return true;
      },
    },
  },
});

良い理由: 標準のWHATWG File API(ブラウザと同じ)を使用し、追加のパッケージは不要で、multipart: false で無効化できます

完全なファイルアップロードパターンについては、examples/core.md を参照してください。


<decision_framework>

決定フレームワーク

スキーマアプローチ

SDLから自動生成された型が必要ですか?
+-- YES --> createSchema(typeDefs + resolversによるスキーマファースト)
+-- NO  --> スキーマ定義で完全なTypeScript推論が必要ですか?
    +-- YES --> コードファーストライブラリ(例: Pothos)-- 結果の GraphQLSchema を Yoga に渡す
    +-- NO  --> バニラ graphql-js GraphQLSchema

サブスクリプション転送

サブスクリプションが必要ですか?
+-- YES --> クライアントに双方向通信が必要ですか?
|   +-- YES --> graphql-ws 経由の WebSocket(ws + graphql-ws パッケージを追加)
|   +-- NO  --> SSE(デフォルト、ゼロ設定、プロキシ経由で動作)
+-- NO  --> サブスクリプションのセットアップは不要

プラグイン選択

機能がYoga固有のプラグインとして利用可能ですか?
+-- YES --> Yogaプラグインを使用(HTTPレベルのフック、実行をスキップ可能)
+-- NO  --> Envelopプラグインを使用(GraphQL実行レベルのフック)

Yoga固有プラグイン(Envelopより優先)

プラグインパッケージYoga固有の理由
レスポンスキャッシュ@graphql-yoga/plugin-response-cacheキャッシュされたクエリの実行をスキップ
永続化操作@graphql-yoga/plugin-persisted-operationsHTTPレイヤーで未知の操作を拒否
Defer/Stream@graphql-yoga/plugin-defer-streamHTTPチャンクエンコーディングでストリーミング
CSRF防止@graphql-yoga/plugin-csrf-preventionパース前にカスタムヘッダーを要求
GraphQL SSE@graphql-yoga/plugin-graphql-sse単一接続SSEモード

</decision_framework>


<red_flags>

注意すべき点(レッドフラグ)

高優先度:

  • GraphQLError を graphql-yoga からインポートしている(graphql からではない)-- パッケージが間違っており、失敗します
  • typeDefs/resolvers オブジェクトを createSchema なしで直接 createYoga に渡している -- v5ではサポートされていません
  • Yoga固有の同等プラグインが存在するのにEnvelopプラグインを使用している -- HTTPレベルの最適化を逃します(Yogaのレスポンスキャッシュはパースを完全にスキップしますが、Envelopの同等品はできません)
  • リゾルバーでプレーンな Error をスローし、クライアントがメッセージを見ることを期待している -- 本番環境では「予期しないエラーが発生しました。」にマスクされます

中優先度:

  • 本番環境でCORSオリジンを設定していない -- デフォルトは * で、制限する必要があります
  • 複数のサーバーインスタンス間でインメモリPubSubを使用している -- イベントが伝播しません(Redisバックアップの createRedisEventTarget を使用)
  • graphql ピア依存関係がない -- graphql-yoga は graphql をピアとして必要とします。両方をインストールしてください
  • スキーマなしで createSchema を呼び出している -- Yogaはスキーマを必要とします。推論はしません

落とし穴とエッジケース:

  • YogaInitialContext.request はFetch APIの Request であり、Node.jsの IncomingMessage ではありません。req.headers ではなく request.headers.get() を使用します
  • v5でプラグイン実行順序が変更されました -- onPluginInit で addPlugin を介して追加されたプラグインは、追加元のプラグインの直後(最後ではない)に実行されるようになりました
  • useResponseCache の session コールバックは、PRIVATEスコープの場合は文字列(ユーザーID)、publicの場合は null を返す必要があります。undefined を返すとキャッシュが壊れます
  • SSEサブスクリプションはHTTP(text/event-stream)を通過します。一部のプロキシはイベントをバッファリングする場合があります。Nginxの場合は X-Accel-Buffering: no を設定します
  • アップロードの File スカラーはWHATWGの File オブジェクトを提供します。.text()、.arrayBuffer()、または .stream() メソッドを使用します(Node.jsの Buffer を直接使用しない)
  • Yogaの組み込みGraphiQLはデフォルトで有効です。本番環境では graphiql: false で無効にします
  • maskedErrors を false に設定すると、スタックトレースを含むすべてのマスキングが無効になります。代わりにカスタムの maskError 関数を使用して選択的に公開します
  • CORSで credentials: true と origin: '*' を組み合わせると、Fetch仕様に従ってブラウザによって拒否されます。正確なオリジンを指定します

</red_flags>


<critical_reminders>

重要なリマインダー

すべてのコードは CLAUDE.md のプロジェクト規約に従うこと

(GraphQLError は 'graphql' からインポートすること。'graphql-yoga' からはインポートしないでください。これは標準の graphql-js エクスポートです)

(Envelop相当のプラグインよりもYoga固有のプラグインを優先すること。YogaプラグインはHTTPレイヤーで動作し、キャッシュ/永続化された結果のためにGraphQLの実行を完全にスキップできます)

(スキーマファーストの場合は 'graphql-yoga' の createSchema を使用すること。v5では createYoga に直接 typeDefs/resolvers オブジェクトを渡すことはサポートされていません)

(すべての数値には名前付き定数を使用すること。タイムアウト、TTL、ポート番号、制限値など)

これらのルールを遵守しないと、インポートエラー、実行時エラー、または重大なタイプミスが発生します。

</critical_reminders>

Individual skills in this repo

This repo contains 11 individual skills — each has its own dedicated page.

関連スキル