Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
本番環境のRailsプロダクトでGraphQL API / GraphQL API on Ra...
Search
roolrool
July 04, 2019
Programming
1
1.6k
本番環境のRailsプロダクトでGraphQL API / GraphQL API on Rails Products in Production
roolrool
July 04, 2019
Tweet
Share
More Decks by roolrool
See All by roolrool
検索のMicroservices化 with Apollo Server
roolrool
2
1.7k
Other Decks in Programming
See All in Programming
もうちょっといいRubyプロファイラを作りたい (2025)
osyoyu
1
440
GitHubとGitLabとAWS CodePipelineでCI/CDを組み比べてみた
satoshi256kbyte
4
240
Android 16 × Jetpack Composeで縦書きテキストエディタを作ろう / Vertical Text Editor with Compose on Android 16
cc4966
2
230
複雑なドメインに挑む.pdf
yukisakai1225
5
1.2k
モバイルアプリからWebへの横展開を加速した話_Claude_Code_実践術.pdf
kazuyasakamoto
0
330
Processing Gem ベースの、2D レトロゲームエンジンの開発
tokujiros
2
130
知っているようで知らない"rails new"の世界 / The World of "rails new" You Think You Know but Don't
luccafort
PRO
1
160
テストコードはもう書かない:JetBrains AI Assistantに委ねる非同期処理のテスト自動設計・生成
makun
0
320
Amazon RDS 向けに提供されている MCP Server と仕組みを調べてみた/jawsug-okayama-2025-aurora-mcp
takahashiikki
1
110
MCPでVibe Working。そして、結局はContext Eng(略)/ Working with Vibe on MCP And Context Eng
rkaga
5
2.3k
「手軽で便利」に潜む罠。 Popover API を WCAG 2.2の視点で安全に使うには
taitotnk
0
860
機能追加とリーダー業務の類似性
rinchoku
2
1.3k
Featured
See All Featured
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
7
840
Building Flexible Design Systems
yeseniaperezcruz
328
39k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
33
2.4k
Producing Creativity
orderedlist
PRO
347
40k
Done Done
chrislema
185
16k
Making Projects Easy
brettharned
117
6.4k
[RailsConf 2023] Rails as a piece of cake
palkan
57
5.8k
Building Better People: How to give real-time feedback that sticks.
wjessup
368
19k
Stop Working from a Prison Cell
hatefulcrawdad
271
21k
jQuery: Nuts, Bolts and Bling
dougneiner
64
7.9k
Bootstrapping a Software Product
garrettdimon
PRO
307
110k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.9k
Transcript
本番環境のRailsプロダクトで GraphQL APIを実装した話 2019/7/4 Ryosuke Yamamoto
2 自己紹介 Ryosuke Yamamoto ( @roolrool ) Webエンジニア 男子シンクロのインストラクター、 Webディレクターを経て2017年1
月にスペースマーケットにジョイン。 開発比率:バックエンド 5:5 フロントエンド
3 担当施策で直近の大きなリリース
4 スペースマーケットEVENTにチケット決済機能追加!
5 決済リリース前 参照系: GraphQL API / 更新系: REST API 決済リリース後
すべてGraphQL APIに移行 スペースマーケットEVENTのAPI構成
6 弊社のGraphQL APIの実装で 工夫しているポイントについて話します! 参考: RailsでGraphQL APIを作る時に悩んだ5つのこと
7 GraphQL
8 • クエリ言語とスキーマ言語からなるAPIのための規格 ◦ クエリ ▪ リクエスト用の言語 ▪ 更新系: Mutation
▪ 参照系: Query ◦ スキーマ ▪ データ型を定義 • 単一エンドポイント ◦ /graphql GraphQLとは
9 スキーマ クエリ レスポンス GraphQLの例 クエリをresolverで処理してレスポンスを返す
10 詳しくはgfxさんの記事をどうぞ
11 ※前提 APIのフレームワークがRailsなので、 graphql-rubyを使用してGraphQL APIを実装
12 話すこと • ページネーション • N+1問題 • 画像/ファイルアップロード • アクセス権限管理
13 ページネーション
14 • 標準のものはRelayのCursor Connectionというカーソルベースのページ ネーション • graphql-rubyもRelayの仕様をサポート ◦ 導入しやすい GraphQLのページネーション
15 カーソル・・?? (初めて知った瞬間の脳内 )
16 • レコードごとにユニークなID(カーソル)を割り当て、そのカーソルを起点として 前後のデータを取得する方式 • レコードの増減によるずれが起きない点がメリット カーソルベースのページネーション
17 カーソルベースのページネーション node (データそのもの) cursor (edgeごとのユニークなID) page(edges+pageInfo) edge ・・・・
18 件数 起点
19 • アプリケーションの仕様上、Offset&Limitページネーションが必要だった • カーソルベースはTwitterタイムラインのような無限スクロールコンテンツには向 いているがページ数を指定したい場合に向かない カーソルベースの問題点
20 ということで Offset&Limitページネーションを実装
21 • Railsのページネーションのデファクトと言えばkaminari ◦ ページネーション機能と関連メソッドを提供するgem ▪ 例) object.page(1).per(10).total_pages: 合計ページ数 Offset&Limitページネーションの実装
22 kaminariを利用して独自のpageInfoを定義
23 カーソルベース ページネーション比較 Offset&Limit
24 N+1問題
25 N+1問題 GraphQLは何も対策しなければサクッとN+1が発生する →resolverを再帰的に実行するのでその度にSQLが 発行されてしまうため
26 サクッとリクエスト N+1問題
27 サクッとN+1 N+1問題
28 N+1?eager loadingだ!(^q^)
29 • GraphQLに先読み(eager loading)は不向き ◦ 回避自体は可能 ◦ どのテーブルがひかれるかどうかはクエリ次第なので先読みしても使わ れない可能性がある ◦
associationのfieldを追加する度に先読みを追加することになる eager loadingで回避? SQLを遅延評価したい
30 • resolverの実行の度にSQLを解決せず、必要なデータを蓄積してから 最後にまとめて解決する • クエリに対して必要なSQLだけを発行するので無駄がない • javascriptならdataloader • Rubyならgraphql-batch
SQLの遅延評価
31 • resolverの実行の度にSQLを解決せず、必要なデータを蓄積してから 最後にまとめて解決する • クエリに対して必要なSQLだけを発行するので無駄がない • javascriptならdataloader • Rubyならgraphql-batch
SQLの遅延評価
32 graphql-batch
33 • Shopify製のライブラリ • 内部で非同期処理のgem(lgierth/promise.rb)を使用している • 単体ではActiveRecordに依存していないが、サンプルが用意されているので その通りに実装すればOK ◦ AssociationLoader
◦ RecordLoader graphql-batchとは
34 AssociationLoader
35 • has_manyな関連レコードを取得する際に使用 • オブジェクトの関連レコードをすべて返す AssociationLoaderとは
36 confidential AssociationLoader定義
37 AssociationLoader呼び出し user.events のイメージ
38 • 下記理由で使用せず ◦ 弊社では独自にページネーションを実装していたため関連をまるまる取 得する形では要件を満たせなかった ◦ resolver内で絞り込みを行った結果を返したかった AssociationLoaderは不採用
39 RecordLoader
40 • belongs_to or has_manyな関連レコードを取得する際に使用 • 指定したモデル名&渡したidのレコードを返す RecordLoaderとは
41 RecordLoader定義
42 RecordLoader呼び出し
43 • idを単体か配列で渡せば遅延評価してくれる ◦ 絞り込んだ結果のレコードセットのidを渡せばいいので柔軟 RecordLoaderを採用
44 • has_many: ◦ RecordLoader#load_many • belongs_to: ◦ RecordLoader#load •
has_one: × ※関連の外部キーを持たない場合 ◦ 良い方法を調査中 各関連の対応状況
45 画像/ファイルアップロード
46 • GraphQLサーバーへのデータの受け渡しはJSONが一般的 • JSONではバイナリデータを扱うことができない ◦ ファイルのアップロードには工夫が必要 GraphQL×ファイルアップロード
47 • multipart/form-dataで送信 ◦ htmlのform submitやjsのFormDataオブジェクトを使用 • Base64にエンコードしてJSONで送信 アップロード方法の選択 Base64にエンコードする方法を採用
48 Base64に対応したアップローダー
49 バックエンドの実装
50 フロントエンドの実装
51 • データサイズが大きくなる ◦ エンコード前と比較して33%増加 • オンメモリで扱うには巨大すぎるデータになってしまう可能性 ◦ リクエストボディのサイズ制限は合わせて必要 Base64の問題点
52 アクセス権限管理 confidential
53 • fieldやObjectTypeそのものに対してアクセス制限を入れたい • ログインユーザーの個人情報や売上データ等 ◦ 誰でも引けると困るデータ ◦ 権限チェックをresolver毎に書くのはつらい アクセス権限管理の目的
54 一括で権限を設定できるライブラリを利用
55 アクセス権限の定義
56 schema定義時に宣言
57 所感など confidential
58 移行してみて • good ◦ ページに対して必要なデータだけを取得するという柔軟なリクエストが出 来るのはやはり良い ◦ 加工したデータを返すfieldなどRESTではレスポンスサイズを気にして持 たせづらかったものも気軽に追加できるようになった
• bad ◦ パフォーマンス分析のツールが揃っていない ▪ Apollo ServerならApollo Engine ▪ New Relic • クライアント側でquery名をユニークにする必要あり
None