Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
カスタムしながら理解するGraphQL Connection
Search
yana-gi
October 25, 2024
Programming
4.2k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
カスタムしながら理解するGraphQL Connection
Kaigi on Rails 2024 (2024.10.25)
yana-gi
October 25, 2024
More Decks by yana-gi
See All by yana-gi
入社して1ヶ月 なんとかやってる話
yanagii
1
460
fjordbootcamp-200123
yanagii
1
720
Other Decks in Programming
See All in Programming
Rでドレミ/Do-Re-Mi_with_R
florets1
0
130
The Rails Doctrine Decade
koic
2
570
AIに “答え“を書かせるのを やめてみた
___akari11
0
120
[ハンズオン]AIへの指示だけで「五目並べ」を作ってみよう
satoshi256kbyte
1
370
contenteditable と日本語入力に向き合う
colorful12
0
200
Herb in Rails 8.2: Your ERB views, now HTML-aware @ Rails World 2026, Austin, Texas
marcoroth
0
210
HTML-in-Canvasで作る未来のWeb UI表現
clockmaker
5
5k
AWS CDKのカスタムリソースでContinuum(旧Security Agent)を実装した話 | Implementing Continuum (formerly Security Agent) via AWS CDK Custom Resource
akihisaikeda
2
150
Railsバージョンを4倍にした話
optim
0
270
sbt 2.0: takeoff
eed3si9n
0
150
Atomic Design, Enforced: Scaling Mobile Design Systems (next.app devCon / droidCon Berlin 2026)
steliosf
PRO
0
170
iOS 27でニュースアプリはどう変わる!? 〜日経電子版の新機能対応と、開発事例から〜
lynnswap
7
13k
Featured
See All Featured
RailsConf 2023
tenderlove
30
1.6k
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
410
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.8k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
2
2.2k
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
360
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.7k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.9k
The Language of Interfaces
destraynor
162
27k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
203
77k
Side Projects
sachag
456
43k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.7k
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
460
Transcript
1 カスタムしながら理解する GraphQL Connection yana-gi Kaigi on Rails 2024 2024.10.25
2 ⾃⼰紹介 minne事業部 プロダクト開発チーム 2022年 中途⼊社 yana-gi やなぎ • 2021年
フィヨルドブートキャンプ卒業 • 2022年〜 GMOペパボ株式会社 Webアプリケーションエンジニア • GitHub : yana-gi • X : @yana_gis • ビールとお茶とみはしのあんみつが好き
3
4 • webの主な技術スタック ◦ Ruby on Rails ◦ Next.js ◦
MySQL • 段階的に移⾏中 ◦ フロント画⾯をRailsからNext.jsへ ◦ APIをREST APIからGraphQL APIへ • GraphQL APIの実装はgraphql-ruby minne
5 • WebはNext.jsに移⾏済み • GraphQL APIに移⾏済み この画⾯のAPIの実装の話👉 minneの検索画⾯
6 質問 🙋
7 GraphQLでAPIを 実装したことがある⽅ 🙋
8 GraphQLについて 初めて聞いた or 馴染みがない⽅ 🙋
9 1. GraphQLとは 1.1. minneでのGraphQL API使⽤例 1.2. minneで新規検索エンジンを導⼊する 1.3. Connection
Type 2. Custom Connection 2.1. クエリをしてからデータを返すまで 2.2. Custom Connectionの実装 2.3. 遅延評価 アジェンダ
GraphQLとは 10 クライアントが必要なデータだけを指定して取得できる データクエリ⾔語及びランタイム ™
None
Products Category Viewer Cart
GraphQLとは 13 エンドポイントで取得するデータを指定する • GET /api/products.json • GET /api/categories.json •
GET /api/cart.json • GET /api/viewer.json 1ページを表⽰するのに4回APIを実⾏する必要がある REST APIの場合
14 • 複数のデータ(ノード)を ⼀つのリクエストで取得する GraphQL APIの場合 GraphQLとは query productPage{ products
{ ... } categories { ... } cart { ... } viewer { ... } }
15 不要なデータのattributesまで取得してしまう Request : GET /api/products.json Response :👉 REST APIの場合
GraphQLとは
16 必要なデータ(ノード)の フィールドを指定できる GraphQL APIの場合 GraphQLとは query productPage { products
{ id name price } categories { id slug name } cart { ... } viewer { ... } }
17 • 既存の検索エンジン(Elasticsearch) • 新しい検索エンジン 新しい検索エンジンの導⼊ 🆕
18 • クライアントが利⽤するminne APIはGraphQL API ◦ クエリは既存の検索エンジンと同じように取得できるように ◦ 既存のクエリのページネーションは カーソルに加えてオフセットでも取得できる
• 新検索エンジンのAPIはREST API ◦ ページネーションはカーソルページネーションのみ 検索エンジン導⼊の要件
19 検索エンジン導⼊の要件
20 • minne側で実装するAPIはGraphQL API ◦ クエリは既存の検索エンジンと同じように取得できるように ◦ 既存のクエリのページネーションは カーソルに加えてオフセットでも取得できる •
新検索エンジンのAPIはREST API ◦ ページネーションはカーソルページネーションのみ 検索エンジン導⼊の要件
21 • オフセットページネーション • カーソルページネーション ページネーションの種類
• データの開始位置を指定する • offset と limit で取得する ◦ offset :
何件⽬から取得するか ◦ limit : 何件取得するか SQLの場合 オフセットページネーション 22 SELECT * FROM products LIMIT 10 OFFSET 30;
• 特定のデータポイント(カーソル)を基準に次のデー タを取得する • 時系列などの特定のデータをキーとして検索する ◦ cursor : ソート可能なデータポイント(カーソル) ◦
limit : 何件取得するか SQLの場合 カーソルページネーション 23 SELECT * FROM products WHERE id > 30 LIMIT 10;
改めて検索エンジンの導⼊要件を確認 24 ◯ オフセット ◯ カーソル ◯ オフセット ✗ カーソル
GraphQLでページネーションを簡単に実装できる GraphQL Connection 25
• Connection: ノード(データ)を リスト形式で取得する • Edge: ノード間の関係性や付加情報 • Node: 実際のデータ本体
Connection のノードの取得クエリ 26 query { products(first: 10) { # ProductConnection Type edges { # ProductEdge Type cursor node { # Product Type name id }, …
nodesからでも取得できる 27 Connection のノードの取得クエリ query { products(first: 10) { nodes
{ name id } } }
開始位置を指定する 28 Connection のノードの取得クエリ # abc以降のデータを10件取得する team { members(first: 10,
after: "abc") { nodes { id name } } }
29 Connection Typeの実装 field :items, Types::ItemType.connection_type, null: false def products
object.products # ActiveRecord Relationの場合 end fieldのTypeをconnection_typeに指定する サポートされているクラスの場合、要素を全て渡す
• 検索エンジンはREST APIで提供されている ◦ ページネーションはoffsetページネーションのみ • 結果を取得したデータを扱うクラスは ActiveRecordではない ◦ Connection
Typeでサポートされていないクラスになりそう ◦ サポートされていない場合は?🤔 改めて今回やりたいこと 30
Custom Connection 31
Custom Connectionを実装する Custom Connection Typeの実装 32 https://graphql-ruby.org/pagination/using_connections.html#return-collections def products #
ActiveRecordのリレーションを取得 relation = object.items # 作成したCustom Connection Typeのインスタンスを返す Connections::ProductsConnection.new(relation) end 参考: https://graphql-ruby.org/pagination/using_connections.html#return-collections
GraphQL::Pagination::Connection を継承したConnection Typeを作る 実装する必要があるメソッドが4つある Custom Connectionの実装 33 参考: https://graphql-ruby.org/pagination/custom_connections.html class
Connections::ProductsConnection < GraphQL::Pagination::Connection def nodes; ...; end # 返すべきノードの配列を取得 def has_next_page; ...; end # 次のページが存在するかを判定 def has_previous_page; ...; end # 前のページが存在するかを判定 def cursor_for(item); ...; end # 指定されたノードのカーソルを⽣成 end
• offset(開始位置)はどこで渡している? ◦ 検索エンジンAPIリクエスト時にoffsetを指定できない ⾃分が疑問に思ったこと 🤔 34
真相を知るために、クエリを実⾏してから値が返却される までを追う • シンプルなActive Recordの場合 • Active RecordかつConnectionの場合 クエリを実⾏してから値が返却されるまで 35
クエリを実⾏してから値が返却されるまで 単純にProductクラスを返す場合 36
クエリを実⾏してから値が返却されるまで Active RecordでConnectionを返す場合 1 37
クエリを実⾏してから値が返却されるまで Active RecordでConnectionを返す場合 2 38
クエリを実⾏してから値が返却されるまで Active RecordでConnectionを返す場合 3 39
クエリを実⾏してから値が返却されるまで Active RecordでConnectionを返す場合 4 40 offsetやlimitの計算
1. 疑問に思ったことの答え • Connection の offset (開始位置)はどうやって決まる? → Connection Class
でcursorから計算している 2. resolverを通った後にConnection Class で offset が決まる わかったこと💡 41
• resolverの時点ではoffsetとlimitが決まっていない • resolverの段階でAPI リクエストをするにもoffsetと limitが決まっていない さらなる疑問🤔 42
• Promiseクラスで遅延評価を⾏う ◦ ※ 既存の検索エンジンの実装を流⽤ 答え 43
遅延評価の流れ1 44
45 遅延評価の流れ2
46 遅延評価の流れ3
クエリをしてから値が返却されるまで1 47
クエリをしてから値が返却されるまで2 48
クエリをしてから値が返却されるまで3 49
クエリをしてから値が返却されるまで4 50
1. GraphQLでページングを⾏うにはConnectionを使う 2. 独⾃のモデルでConnectionを使うにはCustom Connectionを定義する 3. Connection Type Classでoffsetが決まる 4.
offsetを利⽤するためにresolverではPromiseクラスを利 ⽤して遅延評価を⾏う まとめ & 実装してみて分かったこと 51
• 1回のクエリで検索エンジン APIに複数回リクエストがされ ている 1. total_countやhas_next_pageなどを計算するタイミング 2. productsの値を取得するタイミング • total_countやhas_next_pageのみを取得するエンドポイン
トを作ってもらうなどの対応が必要そう 課題 52
• チームメンバー ◦ kazu(@kazuhitonakayam)さん ◦ saki(@Saki-htr)さん • 資料のレビュー ◦ daiki(@doew)さん
◦ pyamaさん • ⼤元のPromiseクラスやCustom Connection Typeの実装 ◦ ogidowさん special thanks 53
54 Thank you! よいGraphQLライフを!