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
GraphQL on Rails
Search
Marc-Andre Giroux
September 24, 2016
Programming
390
2
Share
GraphQL on Rails
Marc-Andre Giroux
September 24, 2016
More Decks by Marc-Andre Giroux
See All by Marc-Andre Giroux
It Depends - Examining GraphQL Myths & Assumptions
xuorig
0
120
So you Want to Distribute your GraphQL Schema?
xuorig
4
870
So you Want to Distribute your GraphQL Schema?
xuorig
0
680
GraphQL Schema Design @ Scale
xuorig
5
2.2k
Continuous Evolution of GraphQL Schemas @ GitHub
xuorig
3
2.1k
GraphQL à Shopify
xuorig
0
270
Exploring GraphQL
xuorig
0
300
GraphQL @ Shopify
xuorig
6
1.8k
From REST to GraphQL
xuorig
9
1.3k
Other Decks in Programming
See All in Programming
条件判定に名前、つけてますか? #phperkaigi #c
77web
2
910
20260315 AWSなんもわからん🥲
chiilog
2
180
PHP 7.4でもOpenTelemetryゼロコード計装がしたい! / PHPerKaigi 2026
arthur1
1
460
ローカルで稼働するAI エージェントを超えて / beyond-local-ai-agents
gawa
1
230
PHPのバージョンアップ時にも役立ったAST(2026年版)
matsuo_atsushi
0
280
へんな働き方
yusukebe
6
2.9k
Smarter Angular mit Transformers.js & Prompt API
christianliebel
PRO
1
110
PHP でエミュレータを自作して Ubuntu を動かそう
m3m0r7
PRO
2
160
Coding as Prompting Since 2025
ragingwind
0
620
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
1.3k
存在論的プログラミング: 時間と存在を記述する
koriym
5
740
見せてもらおうか、 OpenSearchの性能とやらを!
shunta27
1
170
Featured
See All Featured
Why You Should Never Use an ORM
jnunemaker
PRO
61
9.8k
RailsConf 2023
tenderlove
30
1.4k
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
320
Context Engineering - Making Every Token Count
addyosmani
9
790
Side Projects
sachag
455
43k
How STYLIGHT went responsive
nonsquared
100
6k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
22k
GitHub's CSS Performance
jonrohan
1032
470k
Navigating Weather and Climate Data
rabernat
0
150
It's Worth the Effort
3n
188
29k
The Spectacular Lies of Maps
axbom
PRO
1
670
A Tale of Four Properties
chriscoyier
163
24k
Transcript
GraphQL on Rails Marc-Andre Giroux @__xuorig__
@__xuorig__
@__xuorig__ therakiasite.blogspot.com
@__xuorig__ Montreal, Canada
@__xuorig__
@__xuorig__
@__xuorig__ A simple UI component
@__xuorig__
@__xuorig__ What kind of data is needed?
@__xuorig__ Cart Product ProductImage
@__xuorig__ Reusable endpoints (REST)
@__xuorig__ /carts/1 /products/1 /products/2 /products/3 /product_images/1 /product_images/2 /product_images/3
@__xuorig__ Too many round trips!
@__xuorig__ /carts/1?expand=products
@__xuorig__ /carts/1?fields=products(name, description, price)
@__xuorig__ /carts/1?fields=products/name,description,price
@__xuorig__ Custom Endpoints
@__xuorig__ /cart_with_all_the_stuff_i_need
@__xuorig__
@__xuorig__ /cart_with_all_the_stuff_i_need /cart_version_2_with_all_the_things /cart_with_products_and_images /cart_with_products_and_images_with_price_and_taxes my_tightly_coupled_custom_endpoint_including_only_the_things_i_need_bla_bla_bla_bla /cart_with_products_and_images_with_price_and_taxes_but_no_description /cart_with_products_and_images_with_price_and_taxes_but_no_description_v2
@__xuorig__
@__xuorig__ Server Client Updates a view Creates a new view
New view version Model changes Update endpoints Create new endpoint
@__xuorig__ yo, give me the resource with id = abc
OK, here’s the resource with id = abc Client Server
@__xuorig__ yo, give me the resource v2 with id =
abc OK, here’s the resource v2 with id = abc Client Server
@__xuorig__ yo, give me the resource v3 with id =
abc OK, here’s the resource v3 with id = abc Client Server
@__xuorig__ GraphQL
@__xuorig__ What GraphQL is NOT
@__xuorig__ What GraphQL IS
@__xuorig__ { myShop { name } } Field Selection Set
@__xuorig__ { myShop { name } } Lexed Parsed Validated
Executed { “myShop” { “name”: “GitHub” } }
@__xuorig__ { myShop { name } }
@__xuorig__ { myShop { name } }
@__xuorig__
@__xuorig__ { shop(id: 1) { name } }
@__xuorig__ { myShop { name location { city address }
products(orderby: POPULARITY) { name price } } }
@__xuorig__ { “myShop”: { “name”: “Euruko 2016” “location” { “city”:
“Sofia” “address”: “Av. Diagonal 547” } “products”: [{ “name”: “Conference Ticket” “price”: 500000 }, { “name”: “Cool T-Shirt” “price”: 20000 }] } }
@__xuorig__ Type System
@__xuorig__ { myShop { name location { city address }
products(orderby: POPULARITY) { name price } } }
@__xuorig__ { myShop { name location { city address }
products(orderby: POPULARITY) { name price } } }
@__xuorig__ type QueryRoot { myShop: Shop shop(id: Int): Shop }
@__xuorig__ { myShop { name location { city address }
products(orderby: POPULARITY) { name price } } }
@__xuorig__ type Shop { name: String location: Address products(orderby: OrderEnum):
[Product] } enum ProductOrderEnum { PRICE, POPULARITY, ALPHABETICAL }
@__xuorig__ { myShop { name location { city address }
products(orderby: POPULARITY) { name price } } }
@__xuorig__ type Address { city: String address: String }
@__xuorig__ { myShop { name location { city address }
products(orderby: POPULARITY) { name price } } }
@__xuorig__ type Product { name: String price: Int }
@__xuorig__ { myShop { name yolo { swag } }
}
@__xuorig__ { myShop { name yolo { swag } }
} type Shop { name: String location: Address }
@__xuorig__ Introspection
@__xuorig__ query { __schema { … } }
@__xuorig__ Static Validation Code Generation IDE Integration Auto Documentation
@__xuorig__
@__xuorig__
@__xuorig__ { myShop { name location { city address }
products(orderby: POPULARITY) { id name price } } }
@__xuorig__
@__xuorig__ { myShop { name location { city address }
products(orderby: POPULARITY) { id name price } } }
@__xuorig__ Fragments
@__xuorig__ fragment productFields on Product { id name price }
@__xuorig__ { myShop { name location { city address }
products(orderby: POPULARITY) { ...productFields } } }
@__xuorig__ query Fragment Fragment Fragment Fragment
@__xuorig__ Mutations
@__xuorig__ mutation { createProduct(name: “Nice Mug”, price: 10000) { id
name } }
@__xuorig__ Resolving fields
@__xuorig__ github.com/rmosolgo/graphql-ruby
@__xuorig__ ProductType = GraphQL::ObjectType.define do name "Product" description “A product
sold at a shop” # … end
@__xuorig__ field :name do type types.String resolve -> (obj, args,
ctx) { obj.name } end
@__xuorig__ field :price do type types.Int resolve -> (obj, args,
ctx) do obj.subtotal + obj.taxes + obj.shipping_price end end
@__xuorig__ ShopType = ObjectType.define do name “Shop" description "A Shop"
field :products, [ProductType] end
@__xuorig__ QueryType = ObjectType.define do name “Query" description “The Root
of my Schema" field :myShop, ShopType end
@__xuorig__ MySchema = GraphQL::Schema.new( query: QueryRoot, mutation: MutationRoot )
@__xuorig__ POST /graphql
@__xuorig__ module Api class GraphqlController < ApiController def query query_string
= params[:query] variables = params[:variables] context = { current_user: current_user } # ... end end end
@__xuorig__ module Api class GraphqlController < ApiController def query #
... result = MySchema.query( query_string, variables: variables, context: context ) render json: result end end end
@__xuorig__ Drawbacks and solutions
@__xuorig__ N+1 Queries
@__xuorig__ # Product Type field :image do type ImageType resolve
-> (product, args, ctx) do product.image end end # Shop Type field :products do type [ProductType] resolve -> (shop, args, ctx) do shop.products end end
@__xuorig__ Product Load (1.0ms) SELECT "products".* FROM "products" WHERE "products"."shop_id"
= … Image Load (0.9ms) SELECT "images".* FROM "images" WHERE "images"."product_id" = … Image Load (0.2ms) SELECT "images".* FROM "images" WHERE "images"."product_id" = … Image Load (0.1ms) SELECT "images".* FROM "images" WHERE "images"."product_id" = …
@__xuorig__ Solution: Batching + Caching
@__xuorig__ field :image do type ImageType resolve -> (product, args,
ctx) do RecordLoader.for(Image).load(product.image_id) end end
@__xuorig__ HTTP Caching
@__xuorig__ Solution: Client Side Cache
@__xuorig__ Normalized Cache
@__xuorig__ query { shop { products { price } }
} query { shop { product(id: 1) { price } } }
@__xuorig__ { root: { shop: { products: [ Link.new(1) ]
} }, 1: { price: 1000 } }
@__xuorig__ https://github.com/facebook/relay http://www.apollostack.com/
@__xuorig__ Security
@__xuorig__ Query Depth Timeouts Query Complexity
@__xuorig__ Future
@__xuorig__ Subscriptions
@__xuorig__ subscription { productInventorySubscribe { products { inventory } }
}
@__xuorig__ Deferred Queries
@__xuorig__ query { shop { name description products { name
price } } }
@__xuorig__ query { shop { name description products { name
price } } }
@__xuorig__ query { shop { name description products @defer {
name price } } }
@__xuorig__
@__xuorig__ yo, give me the resource with id = abc
OK, here’s the resource with id = abc Client Server
@__xuorig__ Client Server yo, give me the resource with id
= 1 yo, give me the resource with id = 2 yo, give me the resource with id = 3 yo, give me the resource with id = 4
@__xuorig__ oh boy :( Client Server
@__xuorig__ I need that exact data shape (requirements) Here is
everything you can do! (capabilities) Client Server
@__xuorig__ Efficiency
@__xuorig__ Predictability
@__xuorig__ Thank you! Marc-Andre Giroux @__xuorig__