Graphqlまとめ
概要
個人開発でGraphql
を採用したので、これを機にまとめてみました。
型のサポート
Graphql
にはスカラー型
、オブジェクト型
、ルート型
が存在します。(他にもinterfaceやEnumもサポートされています)
スカラー型
プリミティブな型だと、スカラー型と呼ばれる下記が利用できます。
- String(文字列型)
- Int(整数型)
- Float(浮動小数点型)
- Boolean(論理型)
- ID(ID型)
オブジェクト型
Query, Mutationの基盤となる型です。
必須フィールドには!
(エクスクラメーションマーク)をつけて表現することができます。
type User {
id: ID!
name: String
email: String
age: Int
}
また、オブジェクト型のフィールドを指定することも可能です。
type User {
id: ID!
name: String
email: String
age: Int
post: Post // type Post
}
ルート型
Query
, Mutation
, Subscription
が存在します。
それぞれの役割は下記になります。
-
Query
: データ取得 -
Mutation
: データ登録・更新・削除 -
Subscription
: データの監視
Graphqlスキーマ
APIの仕様に当たるのがGraphql
スキーマです。
先ほどのスカラー型
、オブジェクト型
、ルート型
を組み合わせて構築していきます。
先ほどのUser
を全件取得するQuery
を考えてみます。
type Query {
users: [User]
}
また、Graphql
サーバを立ち上げると定義したschema
を確認することができます。
実際にQuery
を実行しながら仕様を確認することもできます。
Graphqlを選択した理由
クエリ言語としての利便性
先ほど挙げた例以外にもGraphQL
はEnum型
, Union型
やInterface型
の定義が可能です。
Interface
のみ軽く触れるとOOP
のようにポリモーフィズムが可能になります。
groupId
を持つAdmin
もUser
として返却したい場合を考えます。
Interface User {
id: ID!
name: String!
}
type Admin implements User {
id: ID!
name: String!
groupId: ID!
}
type Query {
users: [User!]
}
クライアントで生成するクエリではFragmentを利用します。
query getUsers {
users {
name
... on Admin {
groupId
}
}
}
そのほかにも、GraphQL Code Generateを利用することでクエリから型を自動生成してくれます。
参考までに、筆者が利用しているcodegen.ymlです。
(ReactでApollo Serverを利用している場合、pluginsを指定することでhooksも自動生成してくれます。)
schema: ../server/src/graphql/schema.graphql # Graphql Schema
documents: ./src/graphql/query.graphql # Query
generates:
src/graphql/types.ts:
plugins:
- typescript
- typescript-operations
- typescript-react-apollo
スキーマドリブン
GraphQLではスキーマがAPI仕様となるので、スキーマさえ定義すればフロントとバックエンドを並行開発することができます。
Restだと、クライアントがAPIに強く依存します。(エンドポイント、jsonレスポンスなど)
一方GraphQLだと、互いにGraphQLに依存することになります。所謂、「依存性の逆転(Dependency Inversion)」と言えると思います。
もちろん、GraphQLを介したからといってクライアント、サーバーサイドが互いに完全に無関心で開発できるわけではありません※1が「ある程度」疎結合な開発が可能になります。
※1 あるいは完璧なスキーマ定義ができれば可能かもしれません。
クエリによる柔軟なデータ取得・更新
Graphqlクエリを用いて、サーバーからデータを取得/更新できます。
そのためクライアントはRestのようにエンドポイント/HTTPメソッドを意識する必要はありません。
その代わりにクライアントはQueryとMutationを用いてCRUDを実現します。
Fluxとの相性
Fluxではアプリケーションの状態をStore
で持ちます。
Store
は(UI層的な意味合いで)グローバルに呼び出される可能性があるため、トップページにアクセスした際に初期化することが多いかと思います。
ページ遷移の多いモバイルアプリケーションは際たる例です。
初回起動が伸びることと引き換えに、その後の通信を最小限に抑えページ遷移をスムーズに行う必要があります。
これらを実現するためにはページごと(エンドポイントごと)に必要な情報をfetchしてくるRestとは相性があまり良いと言えません。(うまくやればできないこともないかもしれませんが、初回起動時にレスポンスを変えたくなった場合などにクライアントとサーバーの両方の改修が必要になります。)
GraphQLだとこれらの問題が一気に解決します。
サーバーはスキーマのみ意識すればよく、クライアントもまたスキーマとクエリのみを意識すれば良いのです。
Discussion