この記事はGraphQLで使われる文法の入門編です。
よく使われるクエリの文法に焦点を当てて整理しています。
今回はPlaygroundとして一般公開されている以下のサイトを例にして、GraphQLの文法をクエリの実行を試しながら整理していきます。
http://snowtooth.moonhighway.com/
※以下のページより、PlaygroundのIDEをインストールして利用することも可能です。今回は既に公開されているスキーマベースで文法を確認していきます。
https://github.com/prisma/graphql-playground
SQL/RESTとの比較
GraphQLはクエリ言語です。基本的にはQueryとMutation、Subscriptionを使い分けます。
- SQLはデータベース専用のクエリ言語です。
- GraphQLはインターネットのためのクエリ言語です。
SQL/REST | GraphQL | |
---|---|---|
取得 | SELECT | Query |
登録 | INSERT | Mutation |
更新 | UPDATE | Mutation |
削除 | DELETE | Mutation |
- Subscriptionはサーバサイドからプッシュ通知を受けるようなリアルタイム処理で使用されます。
RESTでデータを取得するときと同様に、curlによってデータを取得することができます。
$ curl 'http://.../' -H 'Content-Type: application/json' --data '{"query": "{allLifts {name}}"}'
スキーマ
Playgloundからスキーマを確認してみます。
PlayGroundの右側にSCHEMA
という緑色のタグがあるのでクリックすると、スキーマの定義を確認することができます。
QUERIES/MUTATIONS/SUBSCRIPTIONSと大別されていて、スキーマに定義されたクエリ等の情報が記載されています。
例えば、Liftオブジェクトの一覧を取得したい場合はallLifts
を使用すればよく、どのプロパティを取得できるかまで見ることが可能です。
下記でクエリの文法を見ていきます。
フィールド
クエリ取得できるフィールドは、スカラタイプとオブジェクトタイプの2種類が存在します。
スカラタイプはプログラミング言語でいうところのプリミティブ型を意味しており、GraphQLでは以下の5種類が対応しています。
- Int
- Float
- String
- Boolean
- ID
※IDはユニークな文字列が返却されます。
オブジェクトタイプは1つ以上のフィールドを含んだグループで、JSONの入れ子として表現されます。
シンプルなQuery
データを取得する際の最も基本的なqueryです。allLifts
でLiftsの配列を要求し、配列内の要素としてnameを指定しています。allLifts
は上記のQUERIESで定義されているものです。
query {
allLifts {
name
}
}
このレスポンス結果は以下の通りです。配列の中にname
要素のみが返却されていることがわかります。
配列内の要素としてstatus
を追加してみます。リクエストに欲しい要素を指定することでレスポンスが拡張されます。
query {
allLifts {
name
status
}
}
複数のデータポイントに対するQuery
以下のように組み合わせることで、複数のデータポイントからの取得クエリを1つにまとめることができます。RESTの場合は別APIに対して2度リクエストを発行する必要がありますが、GraphQLの場合はこのような柔軟性により一度のリクエストで完結します。
query liftsAndTrails {
allLifts {
name
status
}
allTrails {
name
difficulty
}
}
※長いのでallLiftsの配列は閉じていますが、それぞれのデータを取得することができました。
一致取得
IDを指定して、1件ヒットしたデータをピンポイントで取得することができます。ORマッパーのfindByIdに相当します。
query jazzCatStatus {
Lift(id: "jazz-cat") {
id
name
status
night
elevationGain
}
}
フィルタ
ステータスを指定することで、取得するデータをフィルタリングすることができます。
query closedLifts {
allLifts(status: CLOSED) {
name
status
}
}
件数の取得
Liftオブジェクトの件数を取得できます。今回は条件指定が必須のため、CLOSEDステータスの件数をカウントしています。
query liftsAndTrails {
liftCount(status:CLOSED)
}
エイリアスの指定
別名として名前を指定することもできます。
query liftsAndTrails {
closed: liftCount(status: CLOSED)
alists: allLifts {
c: name
status
}
blists: allTrails {
name
difficulty
}
}
入れ子
オブジェクトを取得する場合は要素が入れ子になります。
query liftToAccessTrail {
Trail(id:"river-run") {
groomed
accessedByLifts {
name
capacity
}
}
}
フラグメント
冗長な繰り返しを避けるために、フラグメントを使用することができます。
以下ではliftInfo
として3つのプロパティをまとめることで、Trail
とLift
それぞれで同じ宣言を繰り返す必要がなくなります。
fragment liftInfo on Lift {
name
night
elevationGain
}
query {
Trail(id: "river-run") {
name
difficulty
accessedByLifts {
...liftInfo
}
}
Lift(id: "jazz-cat") {
...liftInfo
trailAccess {
name
difficulty
}
}
}
Mutations
Mutationを使って更新が可能です。
まずは現状のステータスを確認してみます。allLifts
を使用して変更したい要素のステータスを見てみましょう。
query all {
allLifts {
id
name
status
}
}
この一番上に表示されたIDが「astra-express」のステータスが現在OPENなので、CLOSEDに変更してみます。
mutation setStatus {
setLiftStatus(id: "astra-express" status: CLOSED) {
id
name
status
}
}
※念の為元のOPENに戻しておきましょう。
mutation setStatus {
setLiftStatus(id: "astra-express" status: OPEN) {
id
name
status
}
}
入力値バリデーション
更新する際に、バリデーションを事前に定義することが可能です。$
文字列の後に続くものが変数となり、:
の後に型と必須チェックを記載しています。
例えば、文字列型で必須にしたい場合は$str:String!
、数値型で必須ではない場合は$num:Int
となります。
※今回はスキーマ自体がID/Status共に必須ではありますが、文法の整理として確認していきます。
mutation setStatus($id:ID! $status:LiftStatus!) {
setLiftStatus(id:$id status: $status) {
id
name
status
}
}
IDを指定して、ステータスをOPENに変更します。
{
"id": "astra-express",
"status": "OPEN"
}
Subscription
subscriptionはサーバからリアルタイムの更新情報をプッシュして欲しい時に使用します。queryやmutationと違い、subscriptionはWebSocketで接続された状態を維持してサーバ側の更新を待ちます。
まずは以下を実行して待ち状態にしましょう。
subscription {
liftStatusChange {
id
name
status
}
}
別タブで同じURLを開きます。別タブからステータス更新のmutationを投げてみます。
mutation setStatus {
setLiftStatus(id: "astra-express" status: OPEN) {
id
name
status
}
}
subscriptionのタブに戻ると、更新されたことをトリガーにデータを取得していることがわかります。下記では2回ステータスをOPENに更新するmutationを投げました。
Introspection
スキーマで定義されているタイプにどんなものがあるかを確認したい場合は、__schema
クエリを投げることで確認できます。
query {
__schema {
types {
name
description
}
}
}
特定のtypeについて詳しくみたい場合は、__type
クエリを使用することで確認できます。
以下ではTrailのすべてのフィールドについて確認することが可能です。
query trailType {
__type(name:"Trail") {
name
fields {
name
description
isDeprecated
}
}
}