【GraphQL】入門編 ~基礎とQuery / Mutationの書き方~ | Offers Tech Blog
概要
こんにちは、Offers を運営している株式会社 overflow の Software Engineer(主戦場はフロントエンド)の Kazuya です。今回は、昨今の WEB アプリケーション開発で採用がされるケースが増えてきている GraphQL について紹介します。
「GraphQL」という名前だけは耳にしたことがあるけど、実際はどういうものなのか分からないという人も多いのではないでしょうか?本記事では、GraphQL 初心者の方でも理解しやすいよう、概要だけでなく RESTful API との違いや具体的な使用方法も掲載していますので、ぜひ参考にしてもらえればと思います。
はじめに
本記事では、GraphQL の基礎と一部実装例を紹介します。GraphQL を扱う上での基礎的な内容ですので、実際のプロダクト開発等では活用できない場合があります。そのことを予めご了承の上、参考にしていただけると幸いです。
GraphQL とは?
GraphQL とは、API 向けに作られたクエリ言語およびクエリを実行するサーバーサイドの実装(ランタイム)のことです。これだけだと分かりづらいのでもう少し簡単にまとめると、「クエリ言語とスキーマ言語で構成された API の規格」と言ったところでしょうか。これでもまだざっくりとしてしまっているので、理解しやすくするために GraphQL の特徴を一部紹介します。
- アプリケーションが呼び出すエンドポイントが 1 つ
- 柔軟なリクエストで最小限のレスポンス
- 1 回のリクエストで複数のリソースにアクセス可能
- スキーマによる型付けにより、堅牢な開発ができる
このように GraphQL は、柔軟性、開発者にとっての使いやすさを向上させるために設計されていることが分かると思います。前提としてなぜ、Meta(旧 Facebook) は GraphQL を開発したのでしょうか。本題に入る前に、開発の経緯と設計に関係のあるグラフ理論について軽く紹介していきます。
GraphQL 開発の経緯とグラフ理論
開発の経緯
GraphQL が開発される以前、Meta(旧 Facebook) は RESTful API(以降、REST)と FQL(Facebook Query Language)を運用し、データを取り扱っていました。しかし、REST には「過剰なデータ取得(オーバーフェッチング)」という課題があり、処理の複雑化やパフォーマンス低下などを引き起こす要因となっています。また、クエリ構造とレスポンス構造に乖離が発生しており、プロダクトの開発/運用する上で課題となっていました。
そこでこれらの課題を改善するために、2012 年に開発がスタートし、2015 年に OSS(オープンソース)として公開されました。その後は、Github を始めとした様々なサービスで導入が進み、現在ではアプリケーション開発における選択肢の 1 つとして注目されています。
GraphQL の導入企業
- Github
- YouTube
- Netflix
- overflow
グラフ理論との関係
GraphQL は、グラフ理論について知っておくことでより理解を深めることができると思います。グラフ理論とは、点(ノード)とそれらを結ぶ線(エッジ)で構成される図形のことです。グラフ理論についての解説は、以下の記事で詳しく解説されていますので、割愛させてもらいます。
そんなグラフ理論ですが、GraphQL のスキーマ設計のベースになっています。GraphQL は名前の通り、グラフ(Graph)を扱う問い合わせ言語という側面をもっており、実際に有向グラフで可視化してみると、構造が類似していることが分かります。
友人関係図(左)とユーザーの GraphQL(右)
GraphQL のメリット/デメリット
メリット
- 柔軟なリクエストで最小限のレスポンス(≒ 通信効率を最適化させやすい)
- 開発をサポートするツールが豊富
- クエリの学習コストが低い
- スキーマをベースとした型補完やチェック
- アプリケーションが呼び出すエンドポイントが 1 つ
デメリット
- REST に比べてキャッシュが複雑になりやすい
- パフォーマンスの分析が難しい
- 複雑な処理を実装するのが難しい
- 動画等の大容量バイナリの扱いが難しい
GraphQL の基礎
スキーマ言語
GraphQL のスキーマ言語は、API の仕様を定義する言語として扱われます。搭載されている型システムにより、クエリやレスポンス、バリデーションなどに対して型を定義できます。
各コンポーネント
- Type
- Field
- Interface
- Union
- Scalar
- Description
クエリ言語
GraphQL のクエリ言語は、データ取得の Query
、データ更新の Mutation
、イベント監視の Subscription
の3種類が存在しており、これらは「オペレーション型」と呼ばれています。
REST および SQL との対応表
Rest | SQL | GraphQL | |
---|---|---|---|
データ取得 | GET | Select | Query |
データ追加 | POST | Create | Mutation |
データ更新 | PATCH | Update | Mutation |
データ削除 | DELETE | Delete | Mutation |
イベント監視 | - | - | Subscription |
Query / Mutation の具体的な書き方
Query
データ取得のクエリである Query
の書き方を解説していきます。まず、今回の解説に使うスキーマは以下の通りで、ユーザーの情報を 1 つ返す user
を定義しています。その際に返すユーザーの情報は User 型で定義されたものになります。
# ルートオペレーション型
type Query {
user: User!
}
# User型
type User {
id: ID!
name: String!
email: String!
}
query GetUser {
user {
id
name
}
}
{
"data": {
"user": {
"id": "hoge",
"name": "foo",
}
}
}
上記の場合、User 型には email
も含まれていますが GetUser
で定義していないため、レスポンスには含まれていません。このように必要に応じてデータを追加したり削ったりできるため、レスポンスを最小限にできます。
Query 内で複数のフィールドを含める方法
Query 内で複数のフィールドを含める際には、以下のように書きます。フィールドを複数含めることができますが、入れ過ぎはパフォーマンスに影響があるため、実装の際は注意しましょう。
# ルートオペレーション型
type Query {
user: User!
users: [User!]
}
# User型
type User {
id: ID!
name: String!
email: String!
}
query GetUser {
user {
id
name
}
users {
id
name
email
}
}
{
"data": {
"user": {
"id": "hoge",
"name": "foo",
}
"users": [
{
"id": "hoge",
"name": "foo",
"email": "foo",
},
{
"id": "hoge",
"name": "foo",
"email": "foo",
}
]
}
}
Fragment
Fragment は、クエリの一部をフラグメント化して再利用する機能のことです。この機能によりフィールド指定の冗長な繰り返しを防ぐことができます。以下の Query では、hoge_user
と foo_user
という 2 つのフィールドがありますが、どちらもレスポンスは共通であることが分かります。
query GetUser {
hoge_user: user {
id
name
}
foo_user: user {
id
name
}
}
上記の Query に Fragment を導入する場合は、以下のように書きます。
query GetUser {
hoge_user: user {
...userFragment
}
foo_user: user {
...userFragment
}
}
fragment userFragment on User {
id
name
}
Fragment は、fragment Fragment名 on 型名 { フィールド }
で定義でき、Query(後述の Mutation も対象)に適応させる場合は、...Fragment名
で展開できます。これは JavaScript のスプレッド構文と同じ書き方です。
Mutation
最後にデータ更新のクエリである Mutation
の書き方を解説していきます。まず、今回の解説に使うスキーマは以下の通りで、ユーザーを登録する createUser
を定義しています。その際に返すユーザーの情報は User 型で定義されたものになります。
# ルートオペレーション型
type Mutation {
createUser(data: UserCreateInput!): User!
}
# User型
type User {
id: ID!
name: String!
email: String!
}
# UserCreateInput型
input UserCreateInput {
id: ID
name: String!
email: String!
}
mutation CreateUser {
createUser(data: {
name: "hoge",
email: "foo@hoge.co.jp"
}) {
name
}
}
{
"data": {
"createUser": {
"name": "hoge",
}
}
}
基本的な書き方は、Query
と変わりません。ですが、createUser
には引数 data
が存在しています。この引数 data
は、UserCreateInput
という型が定義されており、リクエストするためには、ここで定められた値を与える必要があります。今回の場合は name
と email
が、Null を許容しない(必須)になっているため、この2つは必ず設定する必要があるということになります。なお、id
に関しては、Null が許容されている(オプション)のため、設定しなくてもリクエスト可です。
まとめ
今回は GraphQL の基礎と Query と Mutation の書き方についてまとめてみました。本記事で少しでも理解を深めることができていれば幸いです。GraphQL には、本記事で紹介した機能以外にも様々な強力な機能があるので、興味のある方はぜひ触れてみてください。
次回以降は、実際にプロダクト開発でどのように活用していけばいいのかなど、より実践ベースで紹介できればと考えていますので、気長にお待ちいただければと思います。(頑張って早めに書きます)
少々長くなりましたが、最後まで読んで頂き、ありがとうございました。「いいね」していただけると記事執筆の励みになりますので、参考になったと思った方は是非よろしくお願いします!
関連記事
副業転職の Offers 開発チームがお送りするテックブログです。【エンジニア積極採用中】カジュアル面談、副業からのトライアル etc 承っております💪 jobs.overflow.co.jp
Discussion
Mutationの書き方間違っていませんか?
ご指摘ありがとうございました。
誤載を修正してアップデートしました!🙏