スキップしてメイン コンテンツに移動

Reading: 初めてGraphQL - 型の基礎

GraphQLで扱う型はスカラー型とオブジェクト型。スカラー型はプリミティブ型と同じようなイメージでいればOKで、次の5つがある。

* Int
* Float
* String
* Boolean
* ID
IDとStringは、IDは仕様上ユニークにならなければならず、StringはID以外の文字列、という関係性。

特定の型の選択セットとして、フラグメントというものも使える。

framgment listInfo on Lift {
  name
  status
  capacity
  night
  elevationGain
}

と書いて、その内容を次のように使う。

acessedByLifts {
  ...liftInfo
}

フラグメントの中にフラグメントを含めることもできる。
また上記に2つのフラグメントを書くことで、どちらかの型が返ってくる、ということを宣言できるユニオン型というものも用意されている。

また、そうなってくると、この型の時だけあのフィールドがほしい、ということにも当然なってくる。その場合の対応ももちろん実現可能で、インタフェース型を使う。
書籍の中にあった例はもうリンクが切れていて、取得できなかったのでApolloの例を見てみる。

interface Book {
 title: String
 author: Author
}
type TextBook implements Book {
 title: String
 author: Author
 classes: [Class]
}
type ColoringBook implements Book {
 title: String
 author: Author
 colors: [Color]
}
type Query {
 schoolBooks: [Book]
}
query GetBooks {
 schoolBooks {
   title
   ... on TextBook {
     classes {
       name
     }
   }
   ... on ColoringBook {
     colors {
       name
     }
   }
 }
}

出典:Unions and interfaces - Apollo Server - Apollo GraphQL Docs https://www.apollographql.com/docs/apollo-server/schema/unions-interfaces/#interface-type

本の種類に応じて、追加で取得するフィールドを選べるので、これはかなり便利そう。
経験上、特にスキーマファーストで考えてからAPIを自動生成させて簡便にやろうとすると、実装のところでフィールドの取り扱いが地味にしんどくいことがあった。
OpenAPIでクライアントもサーバーもいい感じに扱おうとしたとき、継承までさせるとOpenAPIのドキュメントにうまく表現されないとかそういう細かい話だけれど。

ユニオン型とインタフェース型の使い分けは、両者が全く異なるものならユニオン、共通がありそうならインタフェース、という感じか。


スキーマ情報の調査には次のように"__schema"を使う。

query schemas {
  __schema {
    types {
      name
      description
    }
  }
}

この例だと、各typeについて、nameとdescriptionが取得できる。

その他細かい重要なポイント:
* "!"は必須, "!"がないのはnullable, nullableなものは名前としてない場合もあるし、値としてない(null)場合もあると今のところ理解してる
  - ここ見た Nulls in GraphQL: Cheatsheet https://hasura.io/blog/graphql-nulls-cheatsheet/
* ENUMを定義して応答タイプとしてフィールドに指定することもできる
* リストとNullの制約はリスト自体のNullabilityとリストの中身のNullabilityを考える
  - [Int] nullかもしれないリストで中身はnullかもしれない整数値
  - [Int!] nullかもしれないリストで中身はnullではない整数値
  - [Int]! nullではないリストで中身はnullかもしれない整数値
  - [Int!]! nullではないリストで中身はnullではない整数値
* ページネーションはfirst: 10, start: 20のように指定すれば可能(20番目から10つ取得)
* ソートはソートの方向性とソートの対象のフィールドをENUMで定義した上でデフォルト値を与える
* クエリやミューテーションの引数が増えたら入力型を使うのが良い。オブジェクト型に似ているが、入力型は引数のみに使用できる、ソートもこの入力型を使うと使い回しができて良い

最後に、コメントは

"""
これがコメント
複数行書ける
"""

のようにするか、

"これもコメント"

のようにして、型の定義の前などに置けば、それをGraphQL PlaygroudやGraphiQLでドキュメント化できるだけでなく、イントロスペクションクエリ(query schema, __schemaと書いてたあれ)でも取得できる。