GraphQLガイド - GraphQLのプロトコルと特徴
GraphQLは、Facebook(現Meta)が2012年に開発し、2015年に公開したクエリ言語およびAPI仕様です。REST APIの代替として設計され、クライアントがサーバーから必要なデータを正確に取得できるようにすることを目的としています。
この記事では、GraphQLのプロトコルと特徴について解説し、理解を深めていきます。
GraphQLとは
GraphQLは、クライアントがサーバーに対して必要なデータを正確に指定して取得できるクエリ言語です。従来のREST APIでは、サーバーが決めたエンドポイントから固定のデータ構造を取得する必要がありましたが、GraphQLではクライアントが自由にデータの形を指定できます。
主な特徴
1. 単一エンドポイント
GraphQLでは通常、/graphql
のような単一のエンドポイントを使用します。すべてのクエリ、ミューテーション、サブスクリプションがこのエンドポイントを通じて処理されます。
2. クエリ言語
GraphQLは独自のクエリ言語を提供し、クライアントが必要なデータを正確に指定できます。
1 2 3 4 5 6 7 8 9 10
| query { user(id: "123") { name email posts { title content } } }
|
3. 型システム
GraphQLは強力な型システムを持ち、APIの仕様が明確になります。また、イントロスペクション機能により、スキーマ情報を動的に取得できます。
4. リアルタイム通信
Subscriptions機能により、WebSocketを使用したリアルタイム通信をサポートしています。
プロトコルの詳細
HTTPプロトコルでの実装
GraphQLは主にHTTPプロトコル上で動作します。リクエストボディはJSONです。
以下が基本的なリクエスト形式です。
1 2 3 4 5 6 7 8
| POST /graphql Content-Type: application/json
{ "query": "query { user(id: \"123\") { name email } }", "variables": {}, "operationName": "GetUser" }
|
レスポンス形式
レスポンス形式はJSONです。
1 2 3 4 5 6 7 8 9
| { "data": { "user": { "name": "John Doe", "email": "john@example.com" } }, "errors": null }
|
WebSocketプロトコルでの実装
リアルタイム通信が必要な場合は、WebSocketプロトコルを使用します。
接続確立
1 2 3 4 5
| GET /graphql HTTP/1.1 Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: <key> Sec-WebSocket-Protocol: graphql-ws
|
サブスクリプション例
1 2 3 4 5 6 7
| subscription { userUpdated(userId: "123") { id name email } }
|
GraphQLプロトコルレイヤー
GraphQLは以下のプロトコルレイヤーで動作します。
- HTTP/HTTPS: 主なトランスポートプロトコル
- WebSocket: Subscriptions用のリアルタイム通信
- GraphQL: アプリケーションレベルのクエリ言語
プロトコルスタック
1 2 3 4 5 6 7
| ┌─────────────────┐ │ GraphQL │ ← クエリ言語 ├─────────────────┤ │ HTTP/HTTPS │ ← トランスポート ├─────────────────┤ │ TCP/IP │ ← ネットワーク └─────────────────┘
|
実装例
基本的なクエリ
データの取得にはクエリを利用します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| { "query": ` query GetUser($id: ID!) { user(id: $id) { id name email posts { id title } } } `, "variables": { "id": "123" } }
|
ミューテーション
データの作成、更新にはミューテーションを利用します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| { "query": ` mutation CreateUser($input: CreateUserInput!) { createUser(input: $input) { id name email } } `, "variables": { "input": { "name": "Jane Doe", "email": "jane@example.com" } } }
|
サブスクリプション
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| { "type": "start", "id": "1", "payload": { "query": ` subscription { userUpdated { id name email } } ` } }
|
エラーハンドリング
GraphQLでは、エラーが発生した場合でも部分的なデータを返すことができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| { "data": { "user": { "name": "John Doe", "email": null } }, "errors": [ { "message": "Cannot return null for non-nullable field User.email", "locations": [ { "line": 3, "column": 7 } ], "path": ["user", "email"] } ] }
|
パフォーマンス最適化
1. クエリの最適化
必要なフィールドのみを指定することで、ネットワーク転送量を削減できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| # 良い例:必要なフィールドのみ query { user(id: "123") { name email } }
# 悪い例:不要なフィールドも含む query { user(id: "123") { name email posts { title content comments { text author { name } } } } }
|
2. バッチ処理
複数のクエリを一度に実行することで、ネットワークリクエスト数を削減できます。
1 2 3 4 5 6 7 8 9
| { "query": ` query { user1: user(id: "1") { name email } user2: user(id: "2") { name email } user3: user(id: "3") { name email } } ` }
|
セキュリティ
1. 認証・認可
Authorizationヘッダーに認証・認可トークンを付与します。
1 2 3 4 5 6 7 8
| { "query": "...", "variables": {}, "headers": { "Authorization": "Bearer <token>" } }
|
2. クエリの複雑度制限
悪意のあるクエリによる攻撃を防ぐため、クエリの複雑度を制限することもできます。
1 2 3 4 5 6 7
| const depthLimit = require('graphql-depth-limit'); const server = new ApolloServer({ typeDefs, resolvers, validationRules: [depthLimit(7)] });
|
まとめ
GraphQLは、モダンなWebアプリケーション開発において、REST APIの代替として広く採用されており、REST APIと比較して通信量の削減が見込めます。
今後もGraphQLの普及は進むことが予想され、API設計の標準的なアプローチの一つとして確立されていくと思われます。