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
From REST to GraphQL
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Marc-Andre Giroux
September 06, 2016
Programming
1.3k
9
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
From REST to GraphQL
Marc-Andre Giroux
September 06, 2016
More Decks by Marc-Andre Giroux
See All by Marc-Andre Giroux
It Depends - Examining GraphQL Myths & Assumptions
xuorig
0
140
So you Want to Distribute your GraphQL Schema?
xuorig
4
880
So you Want to Distribute your GraphQL Schema?
xuorig
0
690
GraphQL Schema Design @ Scale
xuorig
5
2.2k
Continuous Evolution of GraphQL Schemas @ GitHub
xuorig
3
2.2k
GraphQL à Shopify
xuorig
0
290
Exploring GraphQL
xuorig
0
310
GraphQL @ Shopify
xuorig
6
1.8k
GraphQL on Rails
xuorig
2
400
Other Decks in Programming
See All in Programming
AIキャラアプリkaiwaの低遅延音声通話基盤をどう作ったか - AWS Gravitonで支える低遅延・低コストAI Agent基盤
mogamit
0
160
Hunting Vulnerabilities in Symfony with LLMs
vinceamstoutz
0
570
Honoでのサプライチェーン侵害対策 〜 3つのライブラリに学ぶ
yusukebe
7
1.8k
トークンをケチるな、設計しろ:GitHub Copilotを賢く使うコンテキスト戦略
ochtum
0
300
エンジニアと一緒にテストコードの設計と実装を改善した話
mototakatsu
0
250
Contextとはなにか
chiroruxx
1
390
AI 輔助遺留系統現代化的經驗分享
jame2408
1
1.2k
TypeScript+Orvalで実現する型安全かつ堅牢でスケーラブルなマルチチャネル通知基盤 / TSKaigi Night talks ~after conference~
d0riven
0
390
コーディングルールの鮮度を保ちたい for SRE NEXT 2026 / keep-fresh-go-internal-conventions-sre-next-2026
handlename
0
130
Snowflake Summitでの新機能 CoCo / CoWork / snowflake-summit-2026-overall-what-new-coco
tatsuhiro
1
220
act1-costs.pdf
sumedhbala
0
190
関数型プログラミングのメリットって何だろう?
wanko_it
0
150
Featured
See All Featured
We Are The Robots
honzajavorek
0
270
The Cult of Friendly URLs
andyhume
79
6.9k
4 Signs Your Business is Dying
shpigford
187
22k
Joys of Absence: A Defence of Solitary Play
codingconduct
1
410
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
230
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
260
Visualization
eitanlees
152
17k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
How GitHub (no longer) Works
holman
316
150k
Ethics towards AI in product and experience design
skipperchong
2
320
Balancing Empowerment & Direction
lara
6
1.2k
Speed Design
sergeychernyshev
33
1.9k
Transcript
From REST to GraphQL Marc-Andre Giroux @__xuorig__
About me
None
A simple UI component
None
What kind of data is needed?
Cart Product ProductImage
Reusable endpoints (REST)
/carts/1 /products/1 /products/2 /products/3 /product_images/1 /product_images/2 /product_images/3
Too many round trips!
/carts/1?expand=products
/carts/1?fields=products(name, description, price)
/carts/1?fields=products/name,description,price
Custom Endpoints
/cart_with_all_the_stuff_i_need
None
/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
None
Server Client Updates a view Creates a new view Product
view v2 Product model changes Update endpoints Create new endpoint
GraphQL
What GraphQL is NOT
What GraphQL IS
{ myShop { name } } Field Selection Set
{ myShop { name } } Lexed Parsed Validated Executed
{ “myShop” { “name”: “GitHub” } }
{ myShop { name } }
{ myShop { name } }
None
{ shop(id: 1) { name } }
{ myShop { name location { city address } products(orderby:
POPULARITY) { name price } } }
{ “myShop”: { “name”: “Full Stack Fest Shop” “location” {
“city”: “Barcelona” “address”: “Av. Diagonal 547” } “products”: [{ “name”: “Conference Ticket” “price”: 500000 }, { “name”: “Cool T-Shirt” “price”: 20000 }] } }
Type System
{ myShop { name location { city address } products(orderby:
POPULARITY) { name price } } }
{ myShop { name location { city address } products(orderby:
POPULARITY) { name price } } }
type QueryRoot { myShop: Shop shop(id: Int): Shop }
{ myShop { name location { city address } products(orderby:
POPULARITY) { name price } } }
type Shop { name: String location: Address products(orderby: OrderEnum): [Product]
} enum ProductOrderEnum { PRICE, POPULARITY, ALPHABETICAL }
{ myShop { name location { city address } products(orderby:
POPULARITY) { name price } } }
type Address { city: String address: String }
{ myShop { name location { city address } products(orderby:
POPULARITY) { name price } } }
type Product { name: String price: Int }
Fragments
{ myShop { name location { city address } products(orderby:
POPULARITY) { id name price } } }
None
{ myShop { name location { city address } products(orderby:
POPULARITY) { id name price } } }
fragment productFields on Product { id name price }
{ myShop { name location { city address } products(orderby:
POPULARITY) { ...productFields } } }
query Fragment Fragment Fragment Fragment
Introspection
query { __schema { … } }
Static Validation Code Generation IDE Integration Auto Documentation
None
None
Resolving fields
type Product { name: String price: Int }
ProductType = GraphQL::ObjectType.define do name "Product" description “A product sold
at a shop” # … end
field :name do type types.String resolve -> (obj, args, ctx)
{ obj.name } end
field :price do type types.Int resolve -> (obj, args, ctx)
do obj.subtotal + obj.taxes + obj.shipping_price end end
field :price do type types.Int resolve -> (obj, args, ctx)
do obj.subtotal + obj.taxes + obj.shipping_price end end
POST /graphql
Mutations
mutation { createProduct(name: “Nice Mug”, price: 10000) { id name
} }
Drawbacks and solutions
N+1 Queries
field :image do type ImageType resolve -> (product, args, ctx)
do product.image end end field :products do type [ProductType] resolve -> (shop, args, ctx) do shop.products end end
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" = …
Solution: Batching + Caching
field :image do type ImageType resolve -> (product, args, ctx)
do RecordLoader.for(Image).load(product.image_id) end end
HTTP Caching
Solution: Client Side Cache
Normalized Cache
Normalized Cache
query { shop { products { price } } }
query { shop { product(id: 1) { price } } }
{ root: { shop: { products: [ Link.new(1) ] }
}, 1: { price: 1000 } }
https://github.com/facebook/relay http://www.apollostack.com/
Security
Query Depth Timeouts Query Complexity
Future
Subscriptions
subscription { productInventorySubscribe { products { inventory } } }
Deferred Queries
query { shop { name description products { name price
} } }
query { shop { name description products { name price
} } }
query { shop { name description products @defer { name
price } } }
None
None
Thank you Marc-Andre Giroux @__xuorig__