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

ZOZOマッチを支えるGraphQL実装の裏側

 ZOZOマッチを支えるGraphQL実装の裏側

2025/11/19 に Flutter ZY で発表した登壇資料です。
https://zozotech-inc.connpass.com/event/371380/

株式会社ZOZO
ブランドソリューション開発本部
新規事業部 フロントエンドブロック
ブロック長 池田 一成

#FlutterZY

Avatar for ZOZO Developers

ZOZO Developers PRO

November 19, 2025
Tweet

More Decks by ZOZO Developers

Other Decks in Technology

Transcript

  1. © ZOZO, Inc. 株式会社ZOZO ブランドソリューション開発本部 新規事業部 フロントエンドブロック ブロック長 池田 一成 2022年

    株式会社ZOZOに中途入社 ZOZOTOWN Androidアプリの開発を担当後 FlutterでのZOZOマッチアプリの開発を担当 GitHub:@ike04 X:@ike_pikmin 2
  2. © ZOZO, Inc. https://zozomatch.jp/ 3 • 2025年6月30日提供開始 • 全身見える直感型マッチングアプリ •

    ファッションジャンル診断などの情報をもとに、ZOZO独自のAIが 「好みの雰囲気」の相手を紹介(最大20人/日) • プロフィールに登録された全身写真からユーザー自身の雰囲気も 分析 • 全身写真と自分らしさを表すキャッチコピーを登録するプロ フィールで、個性や魅力が一目で伝わりやすい設計 • 公的証明書を利用した本人確認や24時間365日の監視体制
  3. © ZOZO, Inc. 4 アジェンダ 1. GraphQLとは
 2. ZOZOマッチでの採用理由
 3.

    GraphQLの実装で苦労したところ
 4. メッセージ機能の実装で工夫したところ

  4. © ZOZO, Inc. 5 GraphQLとは Meta社が公開したAPIのクエリ言語
 REST APIの課題を解決するために開発された 操作タイプ 


    用途
 REST APIでの相当 
 Query
 データの取得
 GET
 Mutation
 データの作成・更新・削除
 POST/PUT/DELETE
 Subscription
 リアルタイムデータの購読
 WebSocket/SSE

  5. © ZOZO, Inc. 7 ZOZOマッチでの採用理由 ZOZOマッチのメッセージ機能の要件 • メッセージの送受信がリアルタイムで反映 される
 •

    オフラインの時に受信したメッセージもオ ンライン復帰時に受信できる
 • 既読の管理ができる
 

  6. © ZOZO, Inc. 8 ZOZOマッチでの採用理由 REST APIの課題 1. リアルタイム性の実装が複雑 ポーリングでは遅延

    WebSocketの実装は複雑 2. 複数回のAPIコール メッセージ一覧、ユーザー情報、既読 状態などを別々に取得する必要がある 3. オーバーフェッチング 不要なデータも含めて取得してしま い、通信量が増加 GraphQLによる対応 WebSocketベースのリアルタイム通信を 標準機能として提供し、リアルタイムでの メッセージの反映を実現 1回のリクエストで必要なデータをまとめて取得可能 必要なフィールドのみを指定して取得でき、通信 量を最適化 Subscription 単一エンドポイント 柔軟なクエリ
  7. © ZOZO, Inc. 9 アジェンダ 1. GraphQLとは
 2. ZOZOマッチでの採用理由
 3.

    GraphQLの実装で苦労したところ
 4. メッセージ機能の実装で工夫したところ

  8. © ZOZO, Inc. 11 メッセージ機能の実装で苦労したところ GraphQL Subscriptionの疎通
 • WebSocketの認証失敗時にログが出力されないため原因特定が難しい
 •

    App Sync側にもSubscriptionにイベントを通知したかのログが残らないため
 アプリの実装かApp Syncの設定の問題なのか切り分けるのが難しい
 → アプリ側で詳細なログを出力できるようにして、コミュニケーションを取ること
   で解決

  9. © ZOZO, Inc. 12 アジェンダ 1. GraphQLとは
 2. ZOZOマッチでの採用理由
 3.

    GraphQLの実装で苦労したところ
 4. メッセージ機能の実装で工夫したところ

  10. © ZOZO, Inc. 14 楽観的更新によるUXの工夫 Optimistic Update(楽観的更新) 
 • ユーザーが行った操作をサーバーからのレスポンスを待たずにUIに反映する手法


    • メリット
 ◦ ネットワーク遅延をユーザーに感じさせないため、アプリが軽快に感じられる
 ◦ すぐに反応があるため、操作に対するフィードバックが直感的で体験が良い
 • 利用例
 ◦ いいねボタンタップ時のUI反映

  11. © ZOZO, Inc. 15 楽観的更新によるUXの工夫 ZOZOマッチではメッセージ送信の際に楽観的更新の処理を追加 1. 即座のUI更新
 ◦ ユーザーがメッセージ送信ボタンをタップすると、一時的なメッセージオブジェクトをローカルに

    追加し、即座にUIに反映
 2. バックグラウンドでの送信 
 ◦ 並行してGraphQL Mutationでサーバーへメッセージを送信
 3. データの同期 
 ◦ Subscription経由でサーバーから正式なメッセージデータを受信後
 一時的なメッセージを置き換え
 

  12. © ZOZO, Inc. 17 AWS AppSyncとの統合における課題と解決策 課題 • バックエンドでAWS AppSyncを利用している場合、標準のWebSocketLinkでは

    AWS AppSync独自の認証形式に対応できない 解決策 • 特別な形式の認証ヘッダーを要求するため
 カスタムのWebSocketLinkを実装する https://github.com/zino-hofmann/graphql-flutter/issues/682
  13. © ZOZO, Inc. 18 AWS AppSyncとの統合における課題と解決策 /// AWS AppSync固有の認証形式に対応するためのリクエストシリアライザー ///

    参考: https://github.com/zino-hofmann/graphql-flutter/issues/682#issuecomm ent-759078492 class _AppSyncRequest extends RequestSerializer { const _AppSyncRequest({required this.authHeader}); final Map<String, dynamic> authHeader; @override Map<String, dynamic> serializeRequest(Request request) => { 'data': jsonEncode({ 'query': printNode(request.operation.document), 'variables': request.variables, }), 'extensions': {'authorization': authHeader}, }; } 固有の認証形式に対応した リクエストシリアライザーを実装 https://docs.aws.amazon.com/appsync/latest/devguide/real-ti me-websocket-client.html#subscription-registration-message
  14. © ZOZO, Inc. 19 AWS AppSyncとの統合における課題と解決策 /// [WebSocketLink]をベースにした、カスタムのWebSocketLink class CustomWebSocketLink

    extends Link { Future<void> connectOrReconnect() async { await _socketClient?.dispose(); _socketClient = SocketClient( url, config: SocketClientConfig( serializer: _AppSyncRequest(authHeader: authHeader), ), onMessage: (message) { logger.info('GraphQL Subscription message: $message'); }, ); } ① WebSocketLinkを自作で実装 serializerに先ほどの自作した AppSyncRequestを設定 独自の形式でリクエストボディを送信 ② onMessageの中でログを出力すること で • Subscriptionの接続が継続してい ること • 購読したイベントの中身 の確認が容易になる
  15. © ZOZO, Inc. 20 アプリバックグラウンド時のSubscription管理 課題 • アプリをバックグラウンドに移行した際にSubscriptionで使用している WebSocket接続が自動的に切断されてしまうことがある →

    OS側でバッテリー消費を抑えるため、バックグラウンドアプリの   ネットワーク接続を制限する 発生する事象 1. アプリをバックグラウンドにすると、WebSocket接続が切断される
 2. この間に送信されたメッセージは、Subscriptionでは受信できない
 3. ユーザーがプッシュ通知でメッセージを確認してアプリに戻っても、受信したはずのメッ セージが表示されない
  16. © ZOZO, Inc. 21 アプリバックグラウンド時のSubscription管理 解決策 1. 自動再接続の実装 autoReconnect: trueの設定により、アプリがフォアグラウンドへ復帰した際WebSocket接続

    を自動的に再開し、Subscriptionの購読を復帰
 2. データの再取得 
 アプリのライフサイクルイベントを監視し、フォアグラウンド復帰時に
 最新のメッセージリストをQueryで再取得

  17. © ZOZO, Inc. 22 まとめ • GraphQLの用途と登場人物を紹介 → リアルタイム通信かつ効率的に必要なデータ取得する際に用いるAPI言語 ◦

    Query:データ取得(GET) ◦ Mutation:データ更新・登録・削除(POST) ◦ Subscription:リアルタイムデータの購読 • GraphQLの実装で苦労した点を紹介 ◦ graphql_codegenで生成されるコードが複雑 ◦ Subscriptionの疎通確認が難しい • メッセージ機能の実装での工夫点を紹介 ◦ 楽観的更新によるUXの改善 ◦ アプリバックグラウンド時のSubscription管理 ◦ AWS AppSyncとの統合における課題と解決策
  18. © ZOZO, Inc. 23 参考資料 1. https://graphql.org/ 2. https://pub.dev/packages/graphql_flutter 3.

    https://pub.dev/packages/graphql_codegen 4. https://developers.cyberagent.co.jp/blog/archives/48956/ 5. https://qiita.com/ryotanny/items/451d770bc191942fa30f