はじめに
本記事は、自分の備忘録も兼ねて書いてます。
前回までは、REST APIの課題(オーバーフェッチ、アンダーフェッチ)と、GraphQLがそれをどう解決するかを見てきました。
今回は、GraphQLが実際にサーバー内部でどのように動いているのか、その仕組み(What/How)について解説します。
GraphQLを構成する3つの要素
GraphQLを理解するためには、以下の3つの要素を知る必要があります。
- スキーマ (Schema): データの「型」と「構造」の定義書
- クエリ (Query): クライアントからの「要求」
- リゾルバ (Resolver): データを実際に取得する「関数」
これらが連携して動くことで、GraphQLは柔軟なデータ取得を実現しています。
1. スキーマ (Schema)
GraphQLの特徴は「型システム (Type System)」を持っていることです。
サーバー側で、「どのようなデータが存在し、どのような関係性を持っているか」を事前に定義します。これをスキーマと呼びます。
前回のブログ記事の例を、GraphQLのスキーマ言語(SDL)で書くと以下のようになります。
# ユーザーの型定義
type User {
id: ID!
name: String!
email: String
address: String
}
# 記事の型定義
type Post {
id: ID!
title: String!
body: String
author: User! # 記事は一人の著者(User)を持つ
comments: [Comment] # 記事は複数のコメント(Comment)を持つ
}
# コメントの型定義
type Comment {
id: ID!
text: String!
}
# クエリの入り口(ルート)の定義
type Query {
user(id: ID!): User
post(id: ID!): Post
}
REST APIでは「URL設計」が重要でしたが、GraphQLではこの「スキーマ設計」が最も重要になります。
2. クエリ (Query)
クライアントは、定義されたスキーマに従って、欲しいデータをJSONのような形式で要求します。
query {
post(id: "p1") {
title
author {
name
}
}
}
3. リゾルバ (Resolver)
ここが「How(どうやって動くか)」の核心です。
スキーマはあくまで「定義」に過ぎません。実際にデータベースからデータを取ってくる処理は、リゾルバと呼ばれる関数が行います。
GraphQLサーバーは、スキーマの各フィールドに対して、1つのリゾルバ関数を持っています。
Python(擬似コード)で書くと、以下のようなイメージです。
# Query.post のリゾルバ
def resolve_post(args):
post_id = args['id']
# DBから記事データを取得して返す
return db.get_post(post_id)
# Post.author のリゾルバ
def resolve_author(parent_post):
author_id = parent_post['author_id']
# DBからユーザーデータを取得して返す
return db.get_user(author_id)
実行フロー
クライアントからクエリが送られてきたとき、サーバーは以下のように動きます。
- 解析 (Parse): クエリを受け取り、構文エラーがないかチェック
- 検証 (Validate): クエリがスキーマの定義と合っているかチェック(存在しないフィールドを要求していないか等)
-
実行 (Execute):
- まず
post(id: "p1")のリゾルバを実行し、記事データを取得 - 次に、その結果に含まれる
authorフィールドのリゾルバを実行し、著者データを取得 - これを、要求されたフィールドがすべて解決されるまで繰り返す。
- まず
- 応答 (Response): 取得した結果を、クエリと同じ形のJSONに整形して返す。
{
"data": {
"post": {
"title": "GraphQL入門",
"author": {
"name": "佐藤 太郎"
}
}
}
}
まとめ
- GraphQLは「スキーマ」「クエリ」「リゾルバ」の3要素で構成される
- スキーマでデータの型を定義し、クエリで欲しいデータを要求し、リゾルバが実際のデータを取得する
- クライアントが自由にデータを要求できるのは、裏側でリゾルバがフィールドごとに独立して動いているから
次回は、実際にPythonとライブラリを使って、簡易的なGraphQLサーバーを構築してみます。