普段はフロントエンドエンジニアとしてJavaScript/TypeScript/Aangular/GraphQLを
メインに開発業務を行なっています。
以前、GraphQLのクライアント側のクエリについて記事にしましたが、今回はGraphQLのスキーマ設計について記載していきたいと思います。

GraphQLのスキーマとは
一言で述べると、GraphQLによるAPIの仕様を表現するものになります。GraphQLでは、APIのデータをRESTのようにエンドポイントの集合としてとらえるのではなく型の集合としてとらえます。この型の集合のことをスキーマと呼びます。
チームで開発する際は、フロントエンドとバックエンドの両方にスキーマによる型定義の情報を把握しておく必要があります。スキーマを定義することで、クライアントサイドとサーバーサイドの両方で、GraphQLのリクエストを型チェック(バリデーション)を行うため、例えば、バックエンドで定義した型と異なるクエリをフロントエンドで実行した場合、正常にデータを取得できずエラーが返ってきます。
GraphQLの型定義
GraphQLの場合、型定義はスキーマ定義言語(SDL:Schema Definition Language)を使用して表現することができます。GraphQLのSDLはアプリが使用する言語やフレームワークに依存することなく使用することができます。それぞれの型はデータに対応するフィールドがあり、そのフィールドが固有の型を持っています。フィールドは、オブジェクトから取り出せるデータの単位を表しています。
スキーマ以下のように記載されます。ファイルの拡張子は基本的には.graphgqlで記載されます。
Photo型が持つIDやString等のフィールドを定義しています。
type Photo { id: ID! name: String! url: String! description: String }
スカラー型
GraphQLにはスカラー型とオブジェクト型が存在します。スカラー型とは、プリミティブ型に近い概念で、合計で5つのスカラー型が用意されています。
- String(文字列型)
- Int(整数型)
- Float(浮動小数点型)
- Boolean(論理型)
- ID(ID型)
整数型と浮動小数点はJSONではnumberで表現されます。文字列型とID型はStringで表現されます。
オブジェクト型は1つ以上のスキーマで定義されているフィールドの集合のことです。JSONの様に入れ子にすることができます。
type Movie { id: ID! ←スカラー型(ID) movieTitle: String ←スカラー型(String) production: Int ←スカラー型(Int) visitors: Int ←スカラー型(Int) directedBy: directedBy ←オブジェクト型(下記directedByスキーマにあるフィールドの集合) } type directedBy { id: ID! ←スカラー型(ID) admission: Boolean ←論理型(Boolean) }
Enum型(列挙型)
TypeScriptに触れたことがある方なら馴染みがあるかと思いますが、GRaphQLではEnum型も定義することができます。Enum型はあらかじめ定められた特定の文字列の一つを返すスカラー型です。
enum PhotoCategory { SELFIE PORTRAIT ACTION } type Photo { id: ID! name: String! url: String! descripion: String! category: PhotoCategory }
リスト
GraphQLではスキーマを作成する際に、リストを作成することも可能です。作成したい型を角括弧で囲むことリストにすることができます。例えば[number]の場合はnumber型のリストを表しています。[PhotoCategory]の場合は、PhotoCategory型のリストを表します。
type bookmarks { title: [string] number: [number!]! photo: [photoCategory] }
ユニオン型
GraphQLのユニオン型は設定している複数の型のうち1つを返す型のことを指します。返したい型をパイプ(|)でつなげることで作成することが出来ます。
union AgendaItem = StudyGroup | Workout type StudyGroup { name: String! subject: String students: [User!] } type Workout { name: String! reps: Int! } Type Query { agenda: [AgendaItem!]! }
インターフェイス
これもTypeScriptを使用したことがある方なら馴染みがあるかと思いますが、GraphQLではインターフェイスも実装することが出来ます。インターフェイスを引き継ぐ際はimplementsを使用します。
interface AgendaItem { name: String! start: String! end: [number!]! } type StudyGroup implements AgendaItem { name: String! start: String! end: [number!]! participants: [User!] topic: String! }
引数
GraphQLのフィールドに引数を追加することが出来ます。スキーマに引数を追加して、データを問い合わせる時に同様に引数を指定することで、複数あるデータの中から特定のデータのみを取得することが出来ます。
フィールドと同じく、引数にも型を指定する必要があります。
type Query { ・ ・ ・ User(githubLogin: String!): User! Photo(id: ID): Photo! }
データページング
データページングとはGraphQLの引数を使用して、取得するデータ量を制限する方法です。開発を進めていくなかで、データ量が増えていくとアプリが一度に全データを取得することは困難になってきます。
GraphQLの引数を使用することで、返されるデータ量を制御することができます。
このデータページングを実装する為に、firstとstartの引数を追加する必要があり、firstがひとつのデータページが返すデータの件数のことで、startで取得するデータの開始位置を指定できます。
下の例では、allUsersクエリでは最新の50件のデータが取得され、allPhotoでは40番目のデータから、最新の20件のデータを取得します。
type Query { ・ ・ ・ allUsers(first: Int=50 start: Int=0): [User!]! allPhoto(first: Int=20 start: int=40): [Photo!]! }
ソート
データを取得する際、データを昇順、降順にソートすることができます。具体的には、enum型と引数を使用してソートします。
enum sortDirection { ASCENDING DESCENDING } Query { allPhotos(sort: sortDirection = DESCENDING): [Photo!]! }
allPhotosクエリにsortの引数を指定しました。sortの引数にはsortDirectionにASCENDING(昇順)とDESCENDING(降順)のいずれかの値を使用することができ、Photoに格納されているデータの全てのフィールドをソートさせることができます。
以上となります。ここまでお読み頂きありがとうございました。
■ おすすめのGraphQLの書籍
■ 参考文献