graphql-architect について
API の設計・最適化に取り組む開発者向けの GraphQL アーキテクチャスキルです。スキーマ設計、フェデレーション、リゾルバー最適化、リアルタイムサブスクリプションを扱います。
主な機能
- 01型安全なスキーマ設計
- 02フェデレーションとスキーマ合成
- 03DataLoader による N+1 対策
- 04リゾルバーのキャッシュとクエリ制限
- 05WebSocket サブスクリプションのパターン
活用シーン
- 01新しい GraphQL API の設計
- 02マイクロサービス間のスキーマ統合
- 03リゾルバーの N+1 クエリ削減
- 04リアルタイムサブスクリプションの追加
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ 404kidwiz/ claude-supercode-skills --skill graphql-architectインストール後、Claude Code で/graphql-architectを入力して読み込まれたか確認します。
同梱ファイルEXAMPLES.mdREFERENCE.md
詳細
GraphQL アーキテクトスキル
目的
スキーマ設計、フェデレーションパターン、リゾルバーの最適化、リアルタイムサブスクリプションを専門とする、GraphQL アーキテクチャの専門知識を提供します。N+1 問題の防止、効率的なキャッシュ、分散システム全体でスケーラブルな API ゲートウェイパターンを備えた、高性能で型安全な GraphQL API を構築します。
使用する場面
- 新しい API の GraphQL スキーマをゼロから設計する
- 複数のサービスにまたがる GraphQL フェデレーションを実装する
- N+1 クエリを防ぐためにリゾルバーを最適化する(DataLoader の実装)
- GraphQL サブスクリプションでリアルタイム機能を構築する
- REST から GraphQL に移行する、または REST と GraphQL のハイブリッド API を設計する
- GraphQL API ゲートウェイパターンを実装する
クイックスタート
このスキルを呼び出す場面:
- 新しい GraphQL スキーマまたはフェデレーションアーキテクチャを設計する
- N+1 クエリのパフォーマンス問題を解決する
- リアルタイムサブスクリプションを実装する
- REST API を GraphQL に移行する
呼び出さない場面:
- シンプルな REST API で十分な場合(api-designer を使用)
- API 層を伴わないデータベーススキーマ設計の場合(database-administrator を使用)
- フロントエンドのデータ取得のみの場合(frontend-developer を使用)
主な機能
スキーマ設計
- ベストプラクティスに基づいた型安全な GraphQL スキーマの作成
- ページネーションパターン(Relay、オフセットベース)の実装
- 入力検証とエラー処理を備えたミューテーションの設計
- スキーマの進化と後方互換性の管理
フェデレーションアーキテクチャ
- マイクロサービス向けの Apollo Federation の実装
- サービスの合成に向けたスキーマステッチングの設定
- サービス間のクエリとミューテーションの管理
- スキーマ合成のための API ゲートウェイの構築
リゾルバーの最適化
- N+1 問題を防ぐための DataLoader の実装
- リゾルバーおよびフィールドレベルでのキャッシュ戦略
- クエリの複雑度分析と深度制限
- 本番環境の最適化に向けた永続化クエリ
リアルタイムサブスクリプション
- WebSocket ベースのサブスクリプションの実装
- サブスクリプションのライフサイクルとクリーンアップの管理
- イベント駆動型バックエンドとの統合
- サブスクリプションの認証と認可への対応
判断フレームワーク
GraphQL と REST の判断基準
| 要素 | GraphQL を使用 | REST を使用 |
|---|---|---|
| クライアントの種類 | ニーズが異なる複数のクライアント | ニーズが予測可能な単一のクライアント |
| データの関係性 | 入れ子が深く、相互に関連するデータ | 関係性が少ないフラットなリソース |
| 過剰なデータ取得 | クライアントごとに必要なデータの一部が異なる | クライアントが通常すべてのフィールドを必要とする |
| データ取得の不足 | 複数回の往復を避けたい | 単一のエンドポイントで十分なデータを提供できる |
| スキーマの進化 | 頻繁に変更があり、後方互換性が必要 | API が安定しており、バージョン管理が許容される |
| リアルタイム性 | サブスクリプションが必要 | ポーリングまたは Webhook で十分 |
スキーマ設計の判断フロー
Schema Design Requirements
│
├─ Single service (monolith)?
│ └─ Schema-first design with single schema
│
├─ Multiple microservices?
│ ├─ Services owned by different teams?
│ │ └─ Apollo Federation
│ └─ Services owned by same team?
│ └─ Schema stitching (simpler)
│
├─ Existing REST APIs to wrap?
│ └─ GraphQL wrapper layer
│
└─ Need backward compatibility?
└─ Hybrid REST + GraphQL
N+1 問題の防止戦略
Resolver Implementation
│
├─ Field resolves to single related entity?
│ └─ DataLoader with batching
│
├─ Field resolves to list of related entities?
│ ├─ List size always small (<10)?
│ │ └─ Direct query acceptable
│ └─ List size unbounded?
│ └─ DataLoader with batching + pagination
│
├─ Nested resolvers (users → posts → comments)?
│ └─ Multi-level DataLoaders
│
└─ Aggregations or counts?
└─ Separate DataLoader for counts
主なワークフロー:DataLoader の実装
問題:N+1 クエリによるパフォーマンス低下
// WITHOUT DataLoader - N+1 problem
const resolvers = {
Post: {
author: async (post, _, { db }) => {
// Executed once per post (N+1 problem!)
return db.User.findByPk(post.userId);
}
}
};
// Query for 100 posts triggers 101 DB queries
解決策:DataLoader でバッチ処理する
import DataLoader from 'dataloader';
// Create loader per request (important!)
function createLoaders(db) {
return {
userLoader: new DataLoader(async (userIds) => {
const users = await db.User.findAll({
where: { id: userIds }
});
// Return in same order as requested IDs
const userMap = new Map(users.map(u => [u.id, u]));
return userIds.map(id => userMap.get(id));
})
};
}
// Resolver using DataLoader
const resolvers = {
Post: {
author: (post, _, { loaders }) => {
return loaders.userLoader.load(post.userId);
}
}
};
// Same query now triggers 2 queries total!
クイックリファレンス:スキーマのベストプラクティス
ページネーションパターン(Relay 形式)
type Query {
users(first: Int, after: String, last: Int, before: String): UserConnection!
}
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type UserEdge {
node: User!
cursor: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
エラー処理パターン
type Mutation {
createUser(input: CreateUserInput!): CreateUserPayload!
}
type CreateUserPayload {
user: User
errors: [UserError!]!
}
type UserError {
field: String
message: String!
code: ErrorCode!
}
enum ErrorCode {
VALIDATION_ERROR
NOT_FOUND
UNAUTHORIZED
CONFLICT
}
危険信号 — エスカレーションが必要な場合
| 状況 | エスカレーションが必要な理由 |
|---|---|
| クエリの複雑度が急増している | 入れ子に制限のないクエリによる DoS の可能性 |
| フェデレーションに循環依存がある | スキーマ設計の問題 |
| 同時接続中のサブスクリプションが 10K 以上 | インフラストラクチャアーキテクチャの問題 |
| 50 以上のフィールドにまたがるスキーマのバージョン管理 | 破壊的変更の管理 |
| サービス間トランザクションが必要 | 分散システムのパターン |
追加リソース
-
詳細な技術リファレンス:REFERENCE.md を参照
- Apollo Federation のセットアップワークフロー
- フィールド単位の認可ディレクティブ
- クエリの複雑度制限
-
コード例とパターン:EXAMPLES.md を参照
- アンチパターン(N+1 クエリ、複雑度制限なし)
- 他のスキルとの統合パターン
- リゾルバーの完全な実装
コメント
Markdown 対応