Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
GraphQLのあまり知られていない魅力 (スキーマの表現力編) / domain modeling with GraphQL Schema
adwd
February 25, 2022
Programming
3
3.6k
GraphQLのあまり知られていない魅力 (スキーマの表現力編) / domain modeling with GraphQL Schema
adwd
February 25, 2022
Tweet
Share
More Decks by adwd
See All by adwd
RxJSで状態を管理する / state management by RxJS
adwd
1
820
Savkin先生から学んだぼくの考えた最強のAngularアプリアーキテクチャ / The best Angular application architecture
adwd
1
640
create-react-app-introduction
adwd
7
1.6k
React/Redux Introduction
adwd
17
4.6k
Other Decks in Programming
See All in Programming
Swift Regex
usamik26
0
200
設計ナイト2022 トランザクションスクリプト
shinpeim
11
2.1k
I/O Extended 2022 in Android ~ Whats new in Android development tools
pluu
0
560
Meet Swift Regex
usamik26
0
370
シェーダー氷山発掘記
logilabo
0
150
LINE Messaging APIの概要 - LINE API総復習シリーズ
uezo
1
180
How we run a Realtime Puzzle Fighting Game on AWS Serverless
falken
0
250
クックパッドマートの失敗したデータ設計 Before / After 大放出
mokuzon
0
180
git on intellij
hiroto_kitamura
0
170
IE Graduation Certificate
jxck
6
4.8k
Imperative is dead, long live Declarative! | Appdevcon
prof18
0
110
"What's new in Swift"の要約 / swift_5_7_summary
uhooi
1
340
Featured
See All Featured
Become a Pro
speakerdeck
PRO
3
840
What's in a price? How to price your products and services
michaelherold
229
9.4k
Visualization
eitanlees
125
11k
Writing Fast Ruby
sferik
612
57k
How to train your dragon (web standard)
notwaldorf
58
3.9k
Why You Should Never Use an ORM
jnunemaker
PRO
47
7.6k
Support Driven Design
roundedbygravity
86
8.5k
The Illustrated Children's Guide to Kubernetes
chrisshort
15
36k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
181
15k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
269
11k
Designing for humans not robots
tammielis
241
23k
Imperfection Machines: The Place of Print at Facebook
scottboms
253
12k
Transcript
GraphQLのあまり知られていない魅力 (スキーマの表現力編) ZOZO Tech Talk #4 - Webフロントエンド×新規事業 株式会社ZOZO
計測プラットフォーム本部 計測システム部 西田 雅博 Copyright © ZOZO, Inc.
© ZOZO, Inc. 株式会社ZOZO 計測プラットフォーム本部 計測システム部 西田 雅博 GraphQL+Reactを極めたい Webフロントエンドエンジニア
Rustもやりたい 2
© ZOZO, Inc. 目次 1. GraphQLとは 2. 一般的に知られているGraphQLのメリット 3. たまたま実感した予想外のGraphQLのメリット
4. こんなGraphQLスキーマです 5. GraphQLスキーマの表現力から得られたメリット 6. まとめ 3
© ZOZO, Inc. GraphQLとは 4
© ZOZO, Inc. GraphQLとは 5 • Meta(Facebook)が開発したクライアントが指定 したデータの形でサーバーがレスポンスを返す クエリ言語 •
https://graphql.org/ • https://spec.graphql.org/October2021/
© ZOZO, Inc. 一般的に知られていそうなGraphQLのメリット • 画面に必要なデータを取得するのに1度のリクエストで済む • リクエスト、レスポンスに静的型が付くのでTypeScriptなどとの相性がいい • GraphiQLやApollo
Sandboxといったプレイグラウンドが便利 • Apollo FederationやSchema Stitchingなどマイクロサービスを束ねる仕組みがある ついでにデメリットも • すべてが POST /graphql になるのでキャッシュや監視のやり方が変わる • クライアント、サーバーともに実装が変わったりと学習コストが必要 6
© ZOZO, Inc. たまたま実感した予想外のGraphQLのメリット • ある新規事業の小さいサービスをREST APIからGraphQLに移行しようとしている • それほど複雑なQuery, MutationがないのでGraphQL特有のメリットはあまりなく、練習くらい
になると思っていた ところが、 • GraphQLスキーマの表現力が高く、REST APIでは表現しきれなかったサーバーとクライアン ト間のドメインロジックが表現できた 7 次のスライドからZOZOMAT for Handsというとある小さいサービスと、そのサー ビスのドメインロジックを表現できたGraphQLスキーマを紹介します
© ZOZO, Inc. 8 • 足のサイズを測ってピッタリのサイズの靴を買えるZOZOMATの指輪版
© ZOZO, Inc. 9 • 足のサイズを測ってピッタリのサイズの靴を買えるZOZOMATの指輪版 • マットの上に手をおいて、音声のガイドに従ってスマホのカメラで色んな 方向から手を撮影すると最適な指輪のサイズを出してくれる •
まだ一般リリースしてなくてこっそりやってます
© ZOZO, Inc. ZOZOMAT for Handsの測定はステップや状態が多い ユーザーに色んな角度から手をスマホで撮影してもらう必要 がある 1.
真上から撮影して左右どっちの手か、マットが平たく置い てあるかなどを判定する 2. マットの色に沿っていろんな角度から手を撮影する 3. 最後に真上からもう一度撮影して完了 このステップごとにサーバーと通信していて、クライアントは今 どのステップにいるのか、次はどのステップかを知る必要があ る 10
© ZOZO, Inc. ZOZOMAT for Handsはエラーがたくさんある • 最初の真上から撮影するとき
◦ 人差し指と中指の間隔が開きすぎている ◦ カメラが手に近すぎる • いろんな角度から撮影しているとき ◦ 指定した色の方向から撮影していない ◦ カメラの角度が高すぎる • などなど • それぞれ対応した音声ガイドを再生するのでエラーハン ドリングが重要 11
© ZOZO, Inc. こんなGraphQLスキーマです 12
© ZOZO, Inc. type Mutation { """ TODOを追加します """ addTodo(text:
String!): Todo } type Todo { id: ID! text: String! status: TodoStatus! foo: FooUnion! } union FooUnion = BarType | BazType | QuxType GraphQLスキーマの基本的な読み方 • Mutation: 実行でデータが変化する操作 ◦ RESTでいうとPUT/POST/DELETE ◦ QueryはGET • addTodoミューテーション ◦ NonNullなStringを引数にとって ◦ NullableなTodoを返す • type Todoで型を宣言 ◦ id, text, status, fooフィールドがある ◦ どれもNonNull • statusはTodoStatus enum • FooUnionは3つのうちいずれかになる 13 enum TodoStatus { TODO DONE }
© ZOZO, Inc. type Mutation { """ processSession 計測ステップを進行します。 sessionIdを指定し、撮影した画像をimageに入れて測定ステップを進めてください。
""" processSession(sessionId: ID!, image: Image!): ProcessSessionResult! } union ProcessSessionResult = ProcessSessionProgressed | ProcessSessionFailed | ProcessSessionCompleted どんなGraphQLスキーマになったか ※説明用に簡略化していますが実際のスキーマと基本的には同じです 14
© ZOZO, Inc. type Mutation { """ processSession 計測ステップを進行します。 sessionIdを指定し、撮影した画像をimageに入れて測定ステップを進めてください。
""" processSession(sessionId: ID!, image: Image!): ProcessSessionResult! } union ProcessSessionResult = ProcessSessionProgressed | ProcessSessionFailed | ProcessSessionCompleted processSession ミューテーション 15 ダブルクォート3つで囲んだところはdescription コメントのようなものだけどMarkdownも使えるれっきとしたドキュメント GraphQLの型で表現しきれないビジネスロジックは無理せずdescriptionを活用する
© ZOZO, Inc. type Mutation { """ processSession 計測ステップを進行します。 sessionIdを指定し、撮影した画像をimageに入れて測定ステップを進めてください。
""" processSession(sessionId: ID!, image: Image!): ProcessSessionResult! } union ProcessSessionResult = ProcessSessionProgressed | ProcessSessionFailed | ProcessSessionCompleted processSession ミューテーション 16 descriptionに書いてあるとおりの処理を行うprocessSessionミューテーション ※GraphQLでファイルアップロードは現状できないので、graphql-multipart-requestを使います
© ZOZO, Inc. type Mutation { """ processSession 計測ステップを進行します。 sessionIdを指定し、撮影した画像をimageに入れて測定ステップを進めてください。
""" processSession(sessionId: ID!, image: Image!): ProcessSessionResult! } union ProcessSessionResult = ProcessSessionProgressed | ProcessSessionFailed | ProcessSessionCompleted processSession ミューテーション 17 processSessionミューテーションの結果はセッションの途中、失敗、完了の3種類
© ZOZO, Inc. union ProcessSessionResult = ProcessSessionProgressed | ProcessSessionFailed |
ProcessSessionCompleted type ProcessSessionProgressed { nextInstruction: CaptureInstruction! } type ProcessSessionFailed { failure: ProcessSessionFailure! } type ProcessSessionCompleted { # このIDで session Query を実行すると測定結果が取得できます。 completedSessionId: ID! } ProcessSessionResult ユニオン 18 processSessionミューテーションの結果は セッションの途中、失敗、完了の3種類
© ZOZO, Inc. union ProcessSessionResult = ProcessSessionProgressed | ProcessSessionFailed |
ProcessSessionCompleted type ProcessSessionProgressed { nextInstruction: CaptureInstruction! } type ProcessSessionFailed { failure: ProcessSessionFailure! } type ProcessSessionCompleted { # このIDで session Query を実行すると測定結果が取得できます。 completedSessionId: ID! } ProcessSessionResult ユニオン 19 セッションの途中の場合は次の測定の指示 enum CaptureInstruction { TOP BLUE # ... }
© ZOZO, Inc. union ProcessSessionResult = ProcessSessionProgressed | ProcessSessionFailed |
ProcessSessionCompleted type ProcessSessionProgressed { nextInstruction: CaptureInstruction! } type ProcessSessionFailed { failure: ProcessSessionFailure! } type ProcessSessionCompleted { # このIDで session Query を実行すると測定結果が取得できます。 completedSessionId: ID! } ProcessSessionResult ユニオン 20 測定ステップ失敗の場合はその理由 enum ProcessSessionFailure { CAMERA_PITCH_TOO_LOW DISTANCE_TOO_CLOSE # ... }
© ZOZO, Inc. union ProcessSessionResult = ProcessSessionProgressed | ProcessSessionFailed |
ProcessSessionCompleted type ProcessSessionProgressed { nextInstruction: CaptureInstruction! } type ProcessSessionFailed { failure: ProcessSessionFailure! } type ProcessSessionCompleted { # このIDで session Query を実行すると測定結果が取得できます。 completedSessionId: ID! } ProcessSessionResult ユニオン 21 測定完了の場合は結果を取得するためのID (結果を出すのに数秒かかるので終わったことだけ通知する)
© ZOZO, Inc. type Mutation { """ processSession 計測ステップを進行します。 sessionIdを指定し、撮影した画像をimageに入れて測定ステップを進めてください。
""" processSession(sessionId: ID!, image: Image!): ProcessSessionResult! } union ProcessSessionResult = ProcessSessionProgressed | ProcessSessionFailed | ProcessSessionCompleted ここまでのまとめ • processSessionを繰り返し使って計測を進める • processSessionは3パターンの結果を返す • 計測途中、失敗、完了それぞれ次の動作に必要な情報 が入っている 22
© ZOZO, Inc. type Query { """ 計測が完了したセッションを取得します。 """ session(id:
ID!): Session } type Session { id: ID! analysis: SessionAnalysis! } union SessionAnalysis = AnalysisInProgress | AnalysisCompleted | AnalysisFailed 測定結果を取得する session クエリ 23
© ZOZO, Inc. type Query { """ 計測が完了したセッションを取得します。 """ session(id:
ID!): Session } type Session { id: ID! analysis: SessionAnalysis! } union SessionAnalysis = AnalysisInProgress | AnalysisCompleted | AnalysisFailed 測定結果を取得する session クエリ 24 測定の結果が分析途中、分析完了、分析失敗の3パターンにな ることがわかる。 それぞれの型の中身は省略するが、途中なら数秒後クエリを再 実行、完了なら結果を表示、失敗ならエラー表示すれば良いこ とがわかる
© ZOZO, Inc. type Mutation { processSession(sessionId: ID!, image: Image!):
ProcessSessionResult! } union ProcessSessionResult = ProcessSessionProgressed | ProcessSessionFailed | ProcessSessionCompleted type Query { session(id: ID!): Session } union SessionAnalysis = AnalysisInProgress | AnalysisCompleted | AnalysisFailed 測定の一連の流れがスキーマから読み取れる 25
© ZOZO, Inc. GraphQLスキーマの表現力から得ら れたメリット 26
© ZOZO, Inc. ドメインモデリングともいえる議論が活発にできた • 最初はREST APIをそのまま移したようなスキーマだったがGitHubのPR上で100件近いコメン トで盛んな議論ができた🔥 27
© ZOZO, Inc. ドメインモデリングともいえる議論が活発にできた • 最初はREST APIをそのまま移したようなスキーマだったがGitHubのPR上で100件近いコメン トで盛んな議論ができた🔥 • 紹介したスキーマは割とシンプルですが原型はかなり違った
◦ Union、EnumといったGraphQLの型システムの恩恵 ◦ 今回は使ってないですがディレクティブも強力です • 以前のREST APIのときは入社間もないこともあって正直言ってあまりドメインを詳細まで理 解できていなかったが、この議論とGraphQLスキーマからよく理解できた 28
© ZOZO, Inc. DDDのドメインモデリングにも使えるのではないか • 先日読んだDomain Modeling Made Functionalという本はF#の型システムを利用してドメイン モデリングしていた
• GraphQLくらいの型システムでも実現可能と思える • マイクロサービスが境界づけられたコンテキストに該当するならそのコンテキストが外部に提 供する能力を可読性高く表現できる…気がする • GraphiQLやApollo Studioで動作が確認しやすいこと、スキーマのドキュメント性が高いことも ドメインエキスパートにやさしいのでは 29
© ZOZO, Inc. まとめ • 小さなサービスにGraphQLを導入した • 予想していなかった効果として、スキーマの表現力によってドメインに関する議論が盛んに 行えた •
GraphQLおすすめです! 30
None