Slide 1

Slide 1 text

© 2012-2022 BASE, Inc. 1 PHPerKaigi 2022 BASE株式会社 永野 峻輔 ( @glassmonkey ) PHPとGraphQL

Slide 2

Slide 2 text

© 2012-2022 BASE, Inc. 2 @glassmonekey #phperkaigi このトークで得られること 実務での経験は乏しいので、コメント募集中です!! オフラインブースにもいます。 ● GraphQLで触ってみるきっかけ ● PHPerがGraphQLを扱う判断材料の手助け

Slide 3

Slide 3 text

© 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

Slide 4

Slide 4 text

© 2012-2022 BASE, Inc. 4 1 2 3 @glassmonekey #phperkaigi GraphQLとは GraphQLを触ってみる PHPとGraphQL 今日話すこと

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

© 2012-2022 BASE, Inc. 6 © 2012-2022 BASE, Inc. 6 その前にREST API

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

© 2012-2022 BASE, Inc. 11 @glassmonekey #phperkaigi GraphQLとは ● Meta(旧Facebook)が2015年頃作った ● API操作のためのクエリ言語 ● スキーマファースト ● 一般的にはhttp プロトコルが使用される。 クエリと結果の例 スキーマの例

Slide 12

Slide 12 text

© 2012-2022 BASE, Inc. 12 1 2 3 @glassmonekey #phperkaigi Query (GET) Mutation (POST, PUT, DELETE) Subscription (データのSubscribe) GraphQLの操作方法

Slide 13

Slide 13 text

© 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

Slide 14

Slide 14 text

© 2012-2022 BASE, Inc. 14 @glassmonekey #phperkaigi GraphQLのスキーマとは 型情報 操作にも型がある。 変数も使える 参考: Relay Cursor Connectionsの仕様と実装方法について クエリと結果の例 データ型

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

© 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 ● 学習コスト ○ パフォーマンス監視の観点やエラートラッキングが変わってくる。 ○ サーバーサイド側のキャッシュ設計は難しい。

Slide 17

Slide 17 text

© 2012-2022 BASE, Inc. 17 © 2012-2022 BASE, Inc. 17 GraphQLを触ってみる

Slide 18

Slide 18 text

© 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 で プレイグラウンドが開く

Slide 19

Slide 19 text

© 2012-2022 BASE, Inc. 19 @glassmonekey #phperkaigi プレイグラウンドの歩き方 https://graphql.org/ GraphQLを記載する。 swapi-graphqlはQueryしかスキーマがない。 そのためQueryしか記載できない。 クエリの結果が返ってくる。 スキーマや説明を見ることができる。 フィールドに何を指定できるかはそれ次第

Slide 20

Slide 20 text

© 2012-2022 BASE, Inc. 20 @glassmonekey #phperkaigi 出演映画情報も追加

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

© 2012-2022 BASE, Inc. 24 @glassmonekey #phperkaigi Relay ● GraphQLのデータ構造の設計パターン1つでページングを加味されている ● GraphQLの実装の1種のMeta社製のRelay(Modern)で採用されている。 ● キャッシュなどのClient側の実装の恩恵も受けやすい。 ● グラフ理論の用語が登場するので予習しておくと吉(Node, Edgeなど) 参考: Relay Cursor Connectionsの仕様と実装方法について

Slide 25

Slide 25 text

© 2012-2022 BASE, Inc. 25 © 2012-2022 BASE, Inc. 25 PHPとGraphQL

Slide 26

Slide 26 text

© 2012-2022 BASE, Inc. 26 1 2 3 @glassmonekey #phperkaigi サーバーサイド側の実装例 クライアントサイド側の実装例 感想 PHPとGraphQL

Slide 27

Slide 27 text

© 2012-2022 BASE, Inc. 27 © 2012-2022 BASE, Inc. 27 サーバーサイド側の実装例

Slide 28

Slide 28 text

© 2012-2022 BASE, Inc. 28 @glassmonekey #phperkaigi 初手は言語別ライブラリ一覧 https://graphql.org/code/

Slide 29

Slide 29 text

© 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/

Slide 30

Slide 30 text

© 2012-2022 BASE, Inc. 30 @glassmonekey #phperkaigi サーバーサイド側で重要な要素 ● スキーマの定義 ● Resolverの実装

Slide 31

Slide 31 text

© 2012-2022 BASE, Inc. 31 @glassmonekey #phperkaigi GraphQL APIのライフサイクル GraphQL Server Basics: GraphQL Schemas, TypeDefs & Resolvers Explained

Slide 32

Slide 32 text

© 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 } 結果例 クエリ例 入力に応じた内容を返却 固定の結果を返却

Slide 33

Slide 33 text

© 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のルーティングに近い 外部定義したスキーマファイル

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

© 2012-2022 BASE, Inc. 35 © 2012-2022 BASE, Inc. 35 クライアント側の実装例

Slide 36

Slide 36 text

© 2012-2022 BASE, Inc. 36 @glassmonekey #phperkaigi クライアント側で重要な要素 ● キャッシュ設計 ● 型生成

Slide 37

Slide 37 text

© 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と変更のあったフィールドを返すようにする

Slide 38

Slide 38 text

© 2012-2022 BASE, Inc. 38 @glassmonekey #phperkaigi 型生成について spawnia/sailor 型生成できるPHPクライアント 生成クライアントはシンプルなので扱いやすい。 2022年3月時点で33スター 設定ファイルとしてsailor.phpを使う

Slide 39

Slide 39 text

© 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

Slide 40

Slide 40 text

© 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 } } クエリから生成したクライアントの利用例

Slide 41

Slide 41 text

© 2012-2022 BASE, Inc. 41 © 2012-2022 BASE, Inc. 41 感想

Slide 42

Slide 42 text

© 2012-2022 BASE, Inc. 42 @glassmonekey #phperkaigi 感想 ● Resolverの実装つらい。 ● スキーマファーストの道のりは険しい。

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

© 2012-2022 BASE, Inc. 46 @glassmonekey #phperkaigi まとめ GraphQLは銀の弾丸ではありません。 REST APIの方が良いときも全然あります。 みなさんの感想も教えてください。 BASEのブースにいるので良かったら現地で握手🤝

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

© 2012-2022 BASE, Inc. 48 © 2012-2022 BASE, Inc. 48 PHPを使わない選択肢

Slide 49

Slide 49 text

© 2012-2022 BASE, Inc. 49 @glassmonekey #phperkaigi Hasura https://hasura.io ● PostgreSQL からGraphQLのエンドポイントを作 ることができる。 ● 無料版はHerokuでDBを立ち上げる ● マイグレーションツールもある。 ● Firebase や Auth0との組み合わせで認証も楽

Slide 50

Slide 50 text

© 2012-2022 BASE, Inc. 50 @glassmonekey #phperkaigi 日本語チュートリアル https://twitter.com/HasuraHQ/status/1504059906751713288 https://hasura.io/learn/ja/graphql/hasura/introduction/

Slide 51

Slide 51 text

© 2012-2022 BASE, Inc. 51 @glassmonekey #phperkaigi 宣伝 https://zenn.dev/glassmonkey/articles/55733b75c08e6a Hasura + Firebaseの組み合わせについてはZennを読んでね!!

Slide 52

Slide 52 text

© 2012-2022 BASE, Inc. 52 @glassmonekey #phperkaigi 絶賛採用活動中!! 一緒にいい感じに開発する 仲間も募集中です https://herp.careers/v1/base 52