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
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
正しくソフトウェアを作る、前提を疑うための認知の視点 / doubt-premise
minodriven
21
7.1k
Make SRE Operations Easier with Azure SRE Agent
kkamegawa
0
8.4k
Signal Forms: Details & Live Coding @enterJS 2026 in Mannheim
manfredsteyer
PRO
0
200
Vue × Nuxt × Oxc どこまで使える?実運用の現在地
andpad
0
310
トークンをケチるな、設計しろ:GitHub Copilotを賢く使うコンテキスト戦略
ochtum
0
210
Agentic UI
manfredsteyer
PRO
0
200
Datadog LLM Observabilityで実現する 安全なLLM Usage 管理
3150
0
120
はてなアカウント基盤 State of the Union
cockscomb
1
900
さぁV100、メモリをお食べ・・・
nilpe
0
160
IBM Bobを活用したレガシーアプリの最新化
oniak3ibm
PRO
1
220
ランチタイムLT会3周年!ランチタイムLT会を3年間続けられたお話
y0hgi
1
110
PHPで使える日時の表現と、その知り方 #frontend_phpcon_do
o0h
PRO
0
270
Featured
See All Featured
Deep Space Network (abreviated)
tonyrice
0
210
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.4k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.5k
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
250
Leo the Paperboy
mayatellez
7
1.9k
Large-scale JavaScript Application Architecture
addyosmani
515
110k
Visualization
eitanlees
152
17k
New Earth Scene 8
popppiees
3
2.4k
Building the Perfect Custom Keyboard
takai
2
800
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
Marketing to machines
jonoalderson
1
5.5k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
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__