Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHPとGraphQL

 PHPとGraphQL

PhperKaigi2022で発表した内容です。
# 概要

昨今宣言的UIの台頭とともに、GraphQLが注目を浴びています。
特にReactではApollo Clientの存在もあり大変便利です。

ではPHPではGraphQLのエコシステムはどうなっているのでしょうか?

今回のトークではGraphQLを活用するメリット・デメリットから、PHPでGraphQLを扱う是非、PHPでGraphQLを扱う場合のライブラリやエコシステムについて解説をします。

# 参考リンク集
- 宣言的UIの状態管理とアーキテクチャ - SwiftUIとGraphQLによる実践
宣言的UIとGraphQLの関わりがわかる良い資料です。
- GraphQL Over Http
httpでGraphQLが同実現されてるかまとめられてます。
- Http Query MethodのDraft
Http Query Methodのrfcのdraftです。2022年4月時点では決まってないので、これからが楽しみですね。
- 200 OK! Error Handling in GraphQL
GraphQLでは実行時エラーをなぜ200で返すのかという解説がまとめられています。解説動画もあります
- Authentication and authorization
認証時のあれこれ
- data loader
N+1対策で
- graphql/swapi-graphql
GraphQLの公式サンプル( swapi-graphql)です。Playgroundはもあります。
- Relay
Relayというライブラリがありますが、その設計パターンをスキーマ設計時に採用しておくとキャッシュ設計やページネーションの対応が楽になりますという紹介です。
- Relay Cursor Connectionsの仕様と実装方法について
- 言語別GraphQLライブラリ一覧
とりあえず初手でみるのおすすめです。
- webonyx/graphql-php
PHPでのサーバーサイド用のGraphQLライブラリとして紹介しました。
- spawnia/sailor
PHPでのクライアントサイド用のGraphQLライブラリとして紹介しました。
- laravel-graphql
スキーマを独自に書く形式。筆者自身はこちらが好みだったりはします。
- light house
eloquentからGraphQLスキーマを生成できる。日本語の情報だとこちらが優勢な気はします。
- hasura
PostgreSQLからGraphQLエンドポイントがかんたんにつくれるSaaSです。
- Hasura + Firebaseで実践GraphQL入門
 筆者の記事の宣伝です。

384e4d8bab8ac2a5e6f64dab1300c491?s=128

glassmonenkey

April 10, 2022
Tweet

More Decks by glassmonenkey

Other Decks in Technology

Transcript

  1. © 2012-2022 BASE, Inc. 1 PHPerKaigi 2022 BASE株式会社 永野 峻輔

    ( @glassmonkey ) PHPとGraphQL
  2. © 2012-2022 BASE, Inc. 2 @glassmonekey #phperkaigi このトークで得られること 実務での経験は乏しいので、コメント募集中です!! オフラインブースにもいます。

    • GraphQLで触ってみるきっかけ • PHPerがGraphQLを扱う判断材料の手助け
  3. © 2012-2022 BASE, Inc. 3 @glassmonekey #phperkaigi 自己紹介 所属 BASE

    株式会社 BASE BANKチーム Engineering Program Manager 資金調達プロダクト「YELL BANK」の開発責任者やってます。 Go, PHP, Pythonを書きつつ時々データエンジニアも。 趣味 Flutterアプリ開発 hasura.ioやsupabaseがマイブーム SNS Twitter: @glassmonekey  Github: https://github.com/glassmonkey 永野 峻輔 (ながの しゅんすけ) PHP ConferenceでLT
  4. © 2012-2022 BASE, Inc. 4 1 2 3 @glassmonekey #phperkaigi

    GraphQLとは GraphQLを触ってみる PHPとGraphQL 今日話すこと
  5. © 2012-2022 BASE, Inc. 5 © 2012-2022 BASE, Inc. 5

    GraphQLとは
  6. © 2012-2022 BASE, Inc. 6 © 2012-2022 BASE, Inc. 6

    その前にREST API
  7. © 2012-2022 BASE, Inc. 7 @glassmonekey #phperkaigi REST API •

    いわゆる我々が一般的にAPIと呼ぶもの。 • GET https://api.example.com/hoge でhogeを取得 • 昨今のフロントエンド事情で複雑化
  8. © 2012-2022 BASE, Inc. 8 @glassmonekey #phperkaigi 昨今のフロント事情 • 宣言的UIの普及

    ◦ React, Swift UI, Jetpack Compose, Flutter など • UI設計はコンポーネント設計と状態管理になってきた。 ◦ View = Component(State) • Typescriptを始め型システムの普及 参考:  宣言的UIの状態管理とアーキテクチャ - SwiftUIとGraphQLによる実践
  9. © 2012-2022 BASE, Inc. 9 @glassmonekey #phperkaigi REST APIで辛いこと •

    宣言的UIとのインピーダンスミスマッチ ◦ アンダーフェッチ(データ不足)・オーバーフェッチ(データ過剰) ◦ フロントエンドに寄せた設計 -> APIの変更追従が辛い。 ◦ バックエンドに寄せた設計 -> 状態管理やAPIコールの最適化が難しい。 • 型構造の提供 ◦ いわゆる open api対応 ◦ フロントへ型システム提供のため ◦ swaggerでyml書くのは辛い。
  10. © 2012-2022 BASE, Inc. 10 © 2012-2022 BASE, Inc. 10

    GraphQLとは
  11. © 2012-2022 BASE, Inc. 11 @glassmonekey #phperkaigi GraphQLとは • Meta(旧Facebook)が2015年頃作った

    • API操作のためのクエリ言語 • スキーマファースト • 一般的にはhttp プロトコルが使用される。 クエリと結果の例 スキーマの例
  12. © 2012-2022 BASE, Inc. 12 1 2 3 @glassmonekey #phperkaigi

    Query (GET) Mutation (POST, PUT, DELETE) Subscription (データのSubscribe) GraphQLの操作方法
  13. © 2012-2022 BASE, Inc. 13 @glassmonekey #phperkaigi HTTP実装についての詳細 • Content

    Typeはapplication/graphql+json (対応してない場合はapplication/json) • 基本的には/graphqlにPOST。SubscriptionはWebSocketで実現される。 • エラーコードについて ◦ バリデーションエラーは400 (構文エラーも含む) ◦ 実行エラーは200。500系は使わない などなど。 今後も変わる可能性はある (HTTP QUERY Methodの登場とか) { "data": { "getInt": 12, "getString": null }, "errors": [ { "message": "Failed to get string!", // ...additional fields... } ] } 実行時エラーの例。 一部取得に失敗することも構造上ありえる。 参考: 200 OK! Error Handling in GraphQL 参考: GraphQL Over HTTP
  14. © 2012-2022 BASE, Inc. 14 @glassmonekey #phperkaigi GraphQLのスキーマとは 型情報 操作にも型がある。

    変数も使える 参考: Relay Cursor Connectionsの仕様と実装方法について クエリと結果の例 データ型
  15. © 2012-2022 BASE, Inc. 15 @glassmonekey #phperkaigi Pros • 最終的なデータ構造の決定権がクライアント側にある。

    ◦ オーバーフェッチは発生しない。 ◦ アンダーフェッチになったときはAPIの開発タイミングと言える。 ◦ 必要なリソースが複雑になりがちな宣言的UIと相性が良い。 • 自然なスキーマファースト ◦ クライアント自動生成などと相性が良い。 ◦ 自然と型安全になる。 ◦ クライアントサイドとサーバーサイドの分業がしやすい。 • エコシステムが豊富 ◦ Playground ◦ ドキュメント自動生成 ◦ クライアントサイドのキャッシュなどなど
  16. © 2012-2022 BASE, Inc. 16 @glassmonekey #phperkaigi Cons • セキュリティ

    ◦ ベストプラクティスが乏しい。気をつけることが多い。 ◦ フレームワークなどで独自実装されているケースはある。 ▪ ex) Applo Client @role https://www.apollographql.com/docs/apollo-server/security/authentication/ • N + 1問題 ◦ データ構造が再帰的に決まるので必然的にN+1は避けづらい ◦ Data loaderという仕組みでなんとかできる。(GraphQLに限った仕組みではない) ▪ https://github.com/graphql/dataloader • 学習コスト ◦ パフォーマンス監視の観点やエラートラッキングが変わってくる。 ◦ サーバーサイド側のキャッシュ設計は難しい。
  17. © 2012-2022 BASE, Inc. 17 © 2012-2022 BASE, Inc. 17

    GraphQLを触ってみる
  18. © 2012-2022 BASE, Inc. 18 @glassmonekey #phperkaigi graphql/swapi-graphql https://github.com/graphql/swapi-graphql 公式のGraphQLサンプル。

    スターウォーズの情報のGraphqlでクエリできる。 https://swapi.dev/ のGraphQLラッパー https://graphql.org/swapi-graphql で プレイグラウンドが開く
  19. © 2012-2022 BASE, Inc. 19 @glassmonekey #phperkaigi プレイグラウンドの歩き方 https://graphql.org/ GraphQLを記載する。

    swapi-graphqlはQueryしかスキーマがない。 そのためQueryしか記載できない。 クエリの結果が返ってくる。 スキーマや説明を見ることができる。 フィールドに何を指定できるかはそれ次第
  20. © 2012-2022 BASE, Inc. 20 @glassmonekey #phperkaigi 出演映画情報も追加

  21. © 2012-2022 BASE, Inc. 21 @glassmonekey #phperkaigi 件数を2件に https://graphql.org/

  22. © 2012-2022 BASE, Inc. 22 @glassmonekey #phperkaigi ページネーション対応

  23. © 2012-2022 BASE, Inc. 23 @glassmonekey #phperkaigi ページネーション対応(2ページ目) https://graphql.org/ 1ページ目の結果

    前ページのendCursorの 値をafterに指定
  24. © 2012-2022 BASE, Inc. 24 @glassmonekey #phperkaigi Relay • GraphQLのデータ構造の設計パターン1つでページングを加味されている

    • GraphQLの実装の1種のMeta社製のRelay(Modern)で採用されている。 • キャッシュなどのClient側の実装の恩恵も受けやすい。 • グラフ理論の用語が登場するので予習しておくと吉(Node, Edgeなど) 参考: Relay Cursor Connectionsの仕様と実装方法について
  25. © 2012-2022 BASE, Inc. 25 © 2012-2022 BASE, Inc. 25

    PHPとGraphQL
  26. © 2012-2022 BASE, Inc. 26 1 2 3 @glassmonekey #phperkaigi

    サーバーサイド側の実装例 クライアントサイド側の実装例 感想 PHPとGraphQL
  27. © 2012-2022 BASE, Inc. 27 © 2012-2022 BASE, Inc. 27

    サーバーサイド側の実装例
  28. © 2012-2022 BASE, Inc. 28 @glassmonekey #phperkaigi 初手は言語別ライブラリ一覧 https://graphql.org/code/

  29. © 2012-2022 BASE, Inc. 29 @glassmonekey #phperkaigi webonyx/graphql-php https://github.com/webonyx/graphql-php PHPのGraphQL関係ではスターが一番多い(と思う)

    薄いweb frameworkみたいな感じでも使える。 SymfonyやLaravelへの拡張とかもある。 https://webonyx.github.io/graphql-php/complementary-tools/
  30. © 2012-2022 BASE, Inc. 30 @glassmonekey #phperkaigi サーバーサイド側で重要な要素 • スキーマの定義

    • Resolverの実装
  31. © 2012-2022 BASE, Inc. 31 @glassmonekey #phperkaigi GraphQL APIのライフサイクル GraphQL

    Server Basics: GraphQL Schemas, TypeDefs & Resolvers Explained
  32. © 2012-2022 BASE, Inc. 32 @glassmonekey #phperkaigi スキーマとResolverの対応 バックエンドサイドのGraphQLの開発 =

    ほぼこれ。 従来のエンドポイントの開発に体感近い。 type Query { hello: String echo(text: String): String } スキーマ例 query { echo(“Some Message”) } “data”: { “hello”: “hi” } “data”: { “echo”: “echo: Some Message” } query { hello } 結果例 クエリ例 入力に応じた内容を返却 固定の結果を返却
  33. © 2012-2022 BASE, Inc. 33 @glassmonekey #phperkaigi PHPでの簡易実装例 $contents =

    file_get_contents('schema.graphql'); $schema = BuildSchema::build($contents); $server = new StandardServer([ 'schema' => $schema, 'fieldResolver' => function ($value, array $arg, $context, ResolveInfo $info) { if ($info->fieldName == 'echo') { return "echo: " . $arg['text']; } if ($info->fieldName == 'hello') { return "hi"; } return null; } ]); $server->handleRequest(); type Query { echo(text: String): String hello: String } RESTのルーティングに近い 外部定義したスキーマファイル
  34. © 2012-2022 BASE, Inc. 34 @glassmonekey #phperkaigi バックエンド実装まとめ • Resolverを中心の開発する

    ◦ 従来のエンドポイント開発に近い • 自動生成ではないからResolverの開発コストが高そうか。 ◦ 個人的にはGoでの99designs/gqlgenが理想 ◦ Resolver以降の処理の実装に専念したい ◦ GraphQLスキーマから自動生成のライブラリご存知でしたら情報求む • データモデル != GraphQLスキーマ ◦ あるResolverの後ろをREST APIに切り出すとかもありえる。 ◦ Relay対応とかも考えると別に捕らえておくのが無難。 ◦ GraphQL は 「DBの操作をフロントに委譲すること」と常にイコールではない。
  35. © 2012-2022 BASE, Inc. 35 © 2012-2022 BASE, Inc. 35

    クライアント側の実装例
  36. © 2012-2022 BASE, Inc. 36 @glassmonekey #phperkaigi クライアント側で重要な要素 • キャッシュ設計

    • 型生成
  37. © 2012-2022 BASE, Inc. 37 @glassmonekey #phperkaigi キャッシュ設計について • GraphQLは構造上バックエンド側でのキャッシュ管理が難しい

    ◦ RelayアーキテクチャにしておくとClient側でキャッシュ管理が楽な側面はある。 • 基本的にはClient側でキャッシュを持つことになる。 ◦ PHPにおいては独自実装するしかない。 参考: https://relay.dev/docs/guides/graphql-server-specification/#schema interface Node { id: ID! } mutation FeedbackLikeMutation($input: FeedbackLikeData!) { feedback_like(data: $input) { feedback { id viewer_does_like like_count } } } Relayアーキテクチャ * データは共通でIDを持つ。 * Mutation(更新)があったときにIDと変更のあったフィールドを返すようにする
  38. © 2012-2022 BASE, Inc. 38 @glassmonekey #phperkaigi 型生成について spawnia/sailor 型生成できるPHPクライアント

    生成クライアントはシンプルなので扱いやすい。 2022年3月時点で33スター 設定ファイルとしてsailor.phpを使う
  39. © 2012-2022 BASE, Inc. 39 @glassmonekey #phperkaigi sailor.phpの設定例 雛形があるのでそれをベースに作る。 https://github.com/spawnia/sailor/blob/master/sailor.php

    exampleにも設定例あるが、 mockの設定がコピペになっててちゃんと動かない(v0.19.0 現在) https://github.com/spawnia/sailor#configuration
  40. © 2012-2022 BASE, Inc. 40 @glassmonekey #phperkaigi クライアント側まとめ • Query(Mutation)から型を生成できる。

    • キャッシュの仕組みはない。頑張る。 // クエリの実行 $obj = Simple\Operations\MyObjectQuery::execute(); // 値 $value = $obj->data?->singleObject->value; // エラー $error = $obj->errors; 自動生成もとのクエリ query MyObjectQuery { singleObject { value } } クエリから生成したクライアントの利用例
  41. © 2012-2022 BASE, Inc. 41 © 2012-2022 BASE, Inc. 41

    感想
  42. © 2012-2022 BASE, Inc. 42 @glassmonekey #phperkaigi 感想 • Resolverの実装つらい。

    • スキーマファーストの道のりは険しい。
  43. © 2012-2022 BASE, Inc. 43 @glassmonekey #phperkaigi Resolverの実装辛い • Laravel

    SymfonyなどのFW拡張で辛さは軽減できそうか ◦ graphql-laravelあたりが使いやすそうな印象(未検証) ▪ データモデルとスキーマが密結合してない ▪ Dataloaderとの実装例のマニュアルもある。 • Resolver != データモデル操作 ◦ 最初はデータモデル操作でも良いとは思う。 ◦ Resolverの先をREST APIに切り出すことも考慮できるようにしてたほうが柔軟性はある ◦ 同じにしてるとRelay対応がつらそう。
  44. © 2012-2022 BASE, Inc. 44 @glassmonekey #phperkaigi スキーマファーストの道のりは険しい • GraphQLスキーマからResolver自動生成がほしい。

    ◦ 個人的にはGoでの99designs/gqlgenが理想 ◦ リゾルバー以降の処理の実装に専念したい ◦ データモデル -> GraphQLスキーマのものはある (ex. lighthouse) ▪ eloquentのモデルからGraphQLスキーマが生成できる。 • 型安全なClient生成は扱いやすそう。 ◦ 薄く程々に型安全が保証されている。 • yml(Swagger)を書く場合とどちらが大変か考えた方が良い。 ◦ Resolverの実装コストと天秤
  45. © 2012-2022 BASE, Inc. 45 @glassmonekey #phperkaigi PHP + GraphQLの感想

    • 入門には適している ◦ eloquentから派生できるlighthouseが特に良さそう。 ◦ スキーマをカスタムしたくなると途端に辛くなる印象はある。 • サーバーサイドで無理しては使わない ◦ Resolverのメンテナンスが大変そうに思える。 ◦ 自動生成系が拡充してから個人的には検討したい。 • クライアント側としては使っていけそう。 ◦ 外部のGraphQLAPIを使うときは自動生成活用していきたい。
  46. © 2012-2022 BASE, Inc. 46 @glassmonekey #phperkaigi まとめ GraphQLは銀の弾丸ではありません。 REST

    APIの方が良いときも全然あります。 みなさんの感想も教えてください。 BASEのブースにいるので良かったら現地で握手🤝
  47. © 2012-2022 BASE, Inc. 47 © 2012-2022 BASE, Inc. 47

    余談
  48. © 2012-2022 BASE, Inc. 48 © 2012-2022 BASE, Inc. 48

    PHPを使わない選択肢
  49. © 2012-2022 BASE, Inc. 49 @glassmonekey #phperkaigi Hasura https://hasura.io •

    PostgreSQL からGraphQLのエンドポイントを作 ることができる。 • 無料版はHerokuでDBを立ち上げる • マイグレーションツールもある。 • Firebase や Auth0との組み合わせで認証も楽
  50. © 2012-2022 BASE, Inc. 50 @glassmonekey #phperkaigi 日本語チュートリアル https://twitter.com/HasuraHQ/status/1504059906751713288 https://hasura.io/learn/ja/graphql/hasura/introduction/

  51. © 2012-2022 BASE, Inc. 51 @glassmonekey #phperkaigi 宣伝 https://zenn.dev/glassmonkey/articles/55733b75c08e6a Hasura

    + Firebaseの組み合わせについてはZennを読んでね!!
  52. © 2012-2022 BASE, Inc. 52 @glassmonekey #phperkaigi 絶賛採用活動中!! 一緒にいい感じに開発する 仲間も募集中です

    https://herp.careers/v1/base 52