Presented at PHPer Kaigi 2019
15分で分かった気になるGraphQLPHPer Kaigi 2019
View Slide
ProfileTwitter: @ichikawa_0829株式会社メルカリ Backendエンジニア
GraphQLとは
https://developer.github.com/v4/explorer/
RESTの問題を解決するために作られたAPIの為のクエリ言語
Appで必要なデータとResponseのデータ構造の乖離“We were frustrated with the differences betweenthe data we wanted to use in our apps and the serverqueries they required.”9/14/2015 by Lee Byronhttps://graphql.org/blog/graphql-a-query-language/
OverfetchingClientのあるページでuser情報の- name- image_uriだけ必要
Overfetching/user/1234Response{“user” {“id”: 1234,“name”: “s-ichikawa”,“image_uri”: “https://xxx/img/1234”,“address”: “東京都A区XYZ”,“birthday”: “1986/08/29”,“gender”: “male”,...}}
Overfetching/user/1234Response{“user” {“id”: 1234,“name”: “s-ichikawa”,“image_uri”: “https://xxx/img/1234”,“address”: “東京都A区XYZ”,“birthday”: “1986/08/29”,“gender”: “male”,...}}必要なのはここだけ
UnderfetchingClientのあるページで指定したuserの友達一覧を出したいusersのfriends全員の- name- image_uriが必要
Underfetching/user/1234Response{“user” {“id”: 1234,…“friends”: [2345,3456,4567,5678]}}
Underfetching/user/2345Response{“user” {“id”: 2345,“name”: “ichikawa_2”,“image_uri”: “https://xxx/img/2345”,…}}
Underfetching/user/2345/user/3456/user/4567・・・
Underfetching/user/2345/user/3456/user/4567・・・Too many round trip
Underfetching/user_for_X/1234Response{“user” {“id”: 1234,…“friends”: [{“id”:2345, “name”:”bさん”,“image_uri”: “https://xxx/img/2345”},{“id”:3456, “name”:”cさん”,“image_uri”: “https://xxx/img/3456”},]}}
似たようなエンドポイントの乱立/user/{id}/user_for_X/{id}/user_for_Y/{id}/user_for_Z/{id}/user_for_admin/{id}…
GraphQLはどう課題解決するか- Appで必要なデータとResponseのデータ構造の乖離- GraphQLではクエリとレスポンスの構造が似ているため、クエリを見ればレスポンスの構造を推測しやすい
GraphQLはどう課題解決するか/graphql
GraphQLはどう課題解決するかRequestquery GetUser {user(id: “1234:) {nameimgfriends {nameimg}}news {titlelink}}/graphql
GraphQLはどう課題解決するかResponse{“data”: {“user”: {“name”: “aさん”,“img”: “https://xxx/img/2345”,“friends”: [{“name”:”bさん”,“img”: “https://xxx/img/2345”}]},“news”: {“title”: “awesome GraphQL”,“link”: “https://xxx/news/1”}}}/graphql
Pros & Cons
GraphQLの強み- データ構造が理解しやすい- 複雑なデータが必要になってもRound Tripが抑えられる- エンドポイント管理が楽- クライアントとサーバ間で型安全なコミュニケーションが可能- 豊富な開発ツール類
GraphQLの弱み- いくつかの操作はRESTより面倒になる場合がある- ファイルアップロード- エラーハンドリング- モニタリング- Cache- パフォーマンス問題- one-to-many、many-to-manyなデータを取得するような場合、サーバ側の実装によってはN+1問題が発生する可能性がある
GraphQLWorkflow
3つのOperation- Query- 情報を取得するために使用される- SQLでいうSELECT- Mutation- 情報を更新するために使用される- SQLでいうINSERT,UPDATE,DELETE- Subscription- 情報の変化をリアルタイムに取得するために使用される
クエリ言語とスキーマ- スキーマ- GraphQL APIの仕様を定義するためのもの- どのような処理ができてどのようなレスポンスが返るかを決める- スキーマが決まるとDocsの自動生成や、Mockの作成が可能になる- クエリ言語- クライアントがGraphQL APIにリクエストするための言語- PHPからDBを操作する際のSQLのようなイメージ
開発の流れSchema DesignImplementsMonitoringSchemaClient APIProductWorkflow Output
with Laravel & Lighthousehttps://lighthouse-php.com/
Schema Design- レスポンスとして得たい型を定義する- 型名- フィールド- 定義した型を得る為のオペレーションを定義する- 必要に応じてENUMやリクエストパラメータとして送信するための型(input型)なども定義できる
Schema Design - with laravel & lighthouse● routes/graphql/schema.graphqlにScheme定義を書くどのクラスがItem型を解決するか紐付ける
Implements - Client- Client側で必要なデータだけを指定してクエリを作成する- クエリをAPI Serverにリクエストする処理を書く- ResponseをページViewに反映させる処理等を書く
Implements - Client with laravel & lighthouse- 今回は横着して時間がないのでPlaygroundで代用- https://github.com/prisma/graphql-playground
Implements - API- API側は採用する言語やライブラリに寄って実装方法は様々- GraphQL処理系の実装は難易度が高いので、基本的には何かしらライブラリを導入することになる- PHPではwebonyx/graphql-phpや- Laravelでやりたいならnuwave/lighthouse辺りが良さそう- オペレーションや型を解決する処理をResolverと呼び、ビジネスロジックやデータアクセス処理を行う- Resolverの集合がGraphQL APIとも言える
Implements - API with laravel & lighthouse- Schemaで紐付けたResolverクラスを書く
Monitoring- GraphQLのモニタリングはRESTの方式をそのまま使えない- エラートラッキング- これまで400系や500系を返していたエラーが発生しても200を返す- そういったエラーをそれぞれどう扱うかを決めて、エラー発生のイベントをトラッキング- パフォーマンス- 単一エンドポイントのためクエリ単位で計測する- クエリ単位だけではなくResolver単位のパフォーマンス測定も必要
Conclusion
GraphQLとは- REST APIの問題を解決する為に開発されたクエリ言語- 仕様は大きく分けてクエリとスキーマで構成される- 3種類のオペレーションがある- Query- Mutation- Subscription- 型付けされるため、クライアントとAPI間で型安全なやり取りが可能になる- RESTを選択する方が適切なケースもある
SubscriptionDirectiveArchitectureSchemaStitchingPHPでどう始めるのかCacheMonitoringAuthorizationCustom Scalar今日話せなかったこと様々な開発Tool
Thank You!Enjoy GraphQL!