GraphQL

目的
仕事でGraphQLを触ることになったが、今までRESTful APIしか開発したことがないのでキャッチアップする

GraphQLとは
API向けに作られたクエリ言語とのこと
クライアント側で必要なデータ構造を定義することで、サーバーからのレスポンスにはその定義されたのと同じ構造のデータが返される
RESTと比較して効率性が良く、必要なデータしか返さないようになっている
参考:https://ja.wikipedia.org/wiki/GraphQL

以下のようなdocumentと呼ばれるDSLを実行することで、GraphQLサーバーからクエリ結果(JSON)
が返されるようになっている
// document
{
tomorrow {
weather
rainyPercent
}
}
{
"tomorrow": {
"weather": "cloudy",
"rainyPercent": 30
}
}

RESTful APIでは curl -X GET http://hoge-api/user
みたいにURLに対してリクエストを行うが、GraphQLでは上記のようなdocumentを単一のAPIエンドポイントへPOSTするようになっている

GraphQLサーバーは受け取ったdocument内のフィールドに対応するデータ値を返す
このフィールドに対応する値の取得を担っているのが resolver
と呼ばれるもの
クライアント側は要求するデータをdocumentに過不足なく記載し、サーバー側はそれに対応するデータをjsonとして返すことで1回のクエリで要求するデータを取得することができる
この resolver の実装はサービス開発者が行う

メリット
RESTful APIでは、欲しいデータを取得するのに幾つかのAPIエンドポイントを叩く必要があるが、
GraphQLでは、documentに欲しいデータを構造化してクエリすることで、一回で欲しいデータを取得することができる。
例えば、UserID 100のユーザー情報と商品ID 239の商品を取得したい場合は、RESTful APIだと、ユーザー情報を取得するエンドポイントと、商品データを取得するエンドポイントの2つに問い合わせを行う必要がある。
GraphQLでは、このエンドポイントに縛られずにdocumentに欲しいデータ(ここでは、ユーザーデータと商品データ)を記述することで1回の問い合わせで2つのデータを取得することができる

Arguments
GraphQLではargumentを用いたクエリ制御が可能になっている
下記のようにdocumentに条件(arguments)を付与することで、それに合致したデータを取得することができる
ここでは、県名が東京で、天気が晴れという条件を付け加えて、その条件に合致した県名と市区町村名 を取得している
// document
{
prefecture(name: "Tokyo") {
prefName
cities(weather: "sunny") {
cityName
rainyPercent
}}}
{
"prefecture": {
{
"prefName": "Tokyo",
"cities": [
{
"cityName": "Shinjuku",
"rainyPercent": 10
},{
"cityName": "Ikebukuro",
"rainyPercent": 0
}]}}}

directives
directivesとは、特定フィールドのクエリ実行可否などの処理制御を、下記のようなアノテーションをフィールドに付与することで実現することができる
特定の条件でレスポンスに含めたい場合は @include(if: Boolean)
を使用する
{
sinjuku {
weather
}
ikebukuro @include(if: false) {
weather
rainyPercent
}}
{
"sinjuku": {
"weather": "cloudy"
}}

GraphQLクライアントの実装にはライブラリの利用は必須ではないが、高機能なものを作る場合は Apollo Client や Relay などのライブラリがよく使われる
GraphQLサーバーの実装には複数の言語が利用可能である(Golangももちろん入っている)

概要とコンセプトは理解できたので、あとは触ってキャッチアップする

ちなみに、GraphQLサーバーをgolangで実装するときは gqlgen が有名(というか会社はgqlgenを採用している)

gqlgenはスキーマ駆動開発を行うライブラリ
GraphQLのスキーマ(shema.graphql)を予め定義して、gqlgen generate
コマンドを実行するとリゾルバの実装コードが自動生成される
ただ、完璧なコードを自動生成してくれるわけではないので手直しする必要が少しある(goaとかだと自動生成されたファイルは基本いじらない)

:kore:
1つのリクエストパターン(メソッド・パス)に対して決まったハンドラを1つ用意すればよかったRESTに対して、無数のパターンが存在するリクエストクエリに対してどのようにレスポンスを作っていけばいいのかというGraphQLサーバー側のロジックは、知識がないと想像しにくいのではないでしょうか