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
Designing and implementing GraphQL API
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Mariusz Gil
May 31, 2019
Programming
120
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Designing and implementing GraphQL API
Mariusz Gil
May 31, 2019
More Decks by Mariusz Gil
See All by Mariusz Gil
Aspect Oriented Programming
mariuszgil
1
350
Discovering unknown with EventStorming ConFoo
mariuszgil
0
330
Game of Developer Life... Deconstructed
mariuszgil
1
210
Back to forgotten roots
mariuszgil
1
460
Go micro with microservices
mariuszgil
5
730
Machine Learning for the rescue
mariuszgil
0
470
Discovering graph structures
mariuszgil
3
570
Introduction to Aerospike with PHP
mariuszgil
8
890
Processing events at scale
mariuszgil
2
410
Other Decks in Programming
See All in Programming
Compiling a real-world CLI tool to native with Static Hermes
tmikov2023
0
120
JAWS-UG 東京支部が始める、JAWS-UG支部コラボ / JAWS-UG lunchtime LT Collaboration
y0hgi
0
270
TechTown - Creating Composable Callables in Contemporary C++
rollbear
0
130
當我們開始不讀 Code - AI Agent 時代,Code Review 與 Clean Code 還剩下什麼?
jame2408
1
200
Web Framework Benchmark Battle 2026, Any%
a_matsuda
2
2k
3回つくってわかった、 定期実行ジョブ基盤の本質情報
takai
0
460
Verilogで学ぶCPU自作入門
uyuki234
8
4.1k
コーディング自動化の次へ。人の介入をゼロにするファクトリーとサポートAIによる実践
timakin
4
3.5k
機械に任せるテスト、人が見るテスト ⽣成AIで引き直した、運⽤保守フェーズの線引き
dske104
0
190
AWSに止められる覚悟してますか?
morizo_1984
2
530
気持ちぃ〜角丸 Squircle
ryu1013
0
310
AIに “答え“を書かせるのを やめてみた
___akari11
0
120
Featured
See All Featured
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
730
Git: the NoSQL Database
bkeepers
PRO
433
67k
Darren the Foodie - Storyboard
khoart
PRO
4
4k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
280
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
2
2k
Art, The Web, and Tiny UX
lynnandtonic
304
22k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.3k
brightonSEO & MeasureFest 2025 - Winning Strategies for Black Friday CRO & PPC - Christian Goodrich
cargoodrich
3
870
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6.1k
The Cult of Friendly URLs
andyhume
79
7k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
53k
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
710
Transcript
DEsigning and implementing Mariusz Gil @mariuszgil GRAPHQL API
None
None
None
None
None
Modeling database theory
Searching data with elastic search
storing data with mYsql 8
Now it is time for… accessing our data from app
Let’s start in 2000
None
All is resource based ]
All is resource based With extra constraints ]
/tweets Resource / collection (or store) archetype
/tweets/123 Resource / document archetype
/tweets/123/media Resource / (embedded) collection archetype
/tweets/123/media/123 Resource / document archetype, inside (embedded) collection
/tweets/123/block Resource / controller archetype
/tweets Resource GET PUT POST PATCH DELETE http method
/tweets Resource GET PUT POST PATCH DELETE http method READ
REPLACE CREATE MODIFY DELETE Action / crUD-style + =
https://nordicapis.com/what-is-the-richardson-maturity-model/
None
Main REST API pros Easy to understand Easy to document
Easy to use Easy to implement Easy to scale Resources are disconnected from representations
Main REST API cons Communication ping-pong Network heavy Time consuming
… Communication ping-pong Network heavy Time consuming
Let’s talk about other options ]
None
Graphql is query language for api With server runtime for
processing queries Using defined type system
Type system ]
type Tweet { id: ID! created_at: String! text: String! }
type User { id: ID! screen_name: String! name: String! profile_image_url: String created_at: String! }
type Tweet { id: ID! created_at: String! text: String! user:
User } type User { id: ID! screen_name: String! name: String! profile_image_url: String created_at: String! }
type Tweet { id: ID! created_at: String! text: String! user:
User } type User { id: ID! screen_name: String! name: String! profile_image_url: String created_at: String! tweets: [Tweet] }
type Tweet { id: ID! created_at: String! text: String! user:
User } type User { id: ID! screen_name: String! name: String! profile_image_url: String created_at: String! tweets: [Tweet] tweets_count: Int }
type Tweet { id: ID! created_at: String! text: String! user:
User } type User { id: ID! screen_name: String! name: String! profile_image_url: String created_at: String! tweets: [Tweet] tweets_count: Int } type Retweet { id: ID! created_at: String! in_reply_to_tweet_id: String! in_reply_to_user_id: String! retweeted_status: Tweet! user: User }
type Tweet { id: ID! created_at: String! text: String! user:
User retweets: [Retweet] retweet_count: Int } type User { id: ID! screen_name: String! name: String! profile_image_url: String created_at: String! tweets: [Tweet] tweets_count: Int } type Retweet { id: ID! created_at: String! in_reply_to_tweet_id: String! in_reply_to_user_id: String! retweeted_status: Tweet! user: User }
type Tweet { id: ID! created_at: String! text: String! user:
User retweets: [Retweet] retweet_count: Int } enum SearchResponse { mixed recent popular } type User { id: ID! screen_name: String! name: String! profile_image_url: String created_at: String! tweets: [Tweet] tweets_count: Int } type Retweet { id: ID! created_at: String! in_reply_to_tweet_id: String! in_reply_to_user_id: String! retweeted_status: Tweet! user: User }
interface Tweet { id: ID! created_at: String! text: String! user:
User retweets: [Retweet] retweet_count: Int }
type TextTweet implements Tweet { id: ID! created_at: String! text:
String! user: User retweets: [Retweet] retweet_count: Int } type MediaTweet implements Tweet { id: ID! created_at: String! text: String! user: User media: [TweetImage] retweets: [Retweet] retweet_count: Int } interface Tweet { id: ID! created_at: String! text: String! user: User retweets: [Retweet] retweet_count: Int }
Communication ]
req resp req resp req resp CLIENT SERVER REST
WHAT YOU ASK IS WHAT YOU GET
req resp CLIENT SERVER GRAPHQL
req resp CLIENT SERVER Reads writes /graphql?q=…
{ twitter { tweet(id: "1134427651672875008") { text } } }
{ "data": { "twitter": { "tweet": { "text": "IT'S @daycamp4devs DAY! :) \\o/ \\o/ \\o/ \\o/ \\o/ https://t.co/RrTFHQKUNt" } } } } REQUEST RESPONSE
{ twitter { tweet(id: "1134427651672875008") { text, created_at } }
} { "data": { "twitter": { "tweet": { "text": "IT'S @daycamp4devs DAY! :) \\o/ \\o/ \\o/ \\o/ \\o/ https://t.co/RrTFHQKUNt” "created_at": "Fri May 31 11:53:23 +0000 2019” } } } } REQUEST RESPONSE
{ twitter { tweet(id: "1134427651672875008") { text, created_at, user }
} } WRONG REQUEST! REQUEST RESPONSE
{ twitter { tweet(id: "1134427651672875008") { text, created_at, user {
screen_name } } } } { "data": { "twitter": { "tweet": { "text": "IT'S @daycamp4devs DAY! :) \\o/ \\o/ \\o/ \\o/ \\o/ https://t.co/RrTFHQKUNt”, "created_at": "Fri May 31 11:53:23 +0000 2019”, "user": { "screen_name": "CalEvans" } } } } } REQUEST RESPONSE
Let see it in action Almost live ;)
None
Query execution
{ twitter { tweet(id: "1134427651672875008") { text, created_at } }
} { "data": { "twitter": { "tweet": { "text": "IT'S @daycamp4devs DAY! :) \\o/ \\o/ \\o/ \\o/ \\o/ https://t.co/RrTFHQKUNt” "created_at": "Fri May 31 11:53:23 +0000 2019” } } } } REQUEST RESPONSE
import { GraphQLSchema, GraphQLObjectType, GraphQLID, GraphQLString, GraphQLNonNull, GraphQLInt, GraphQLList, GraphQLScalarType,
GraphQLEnumType } from "graphql"; DATA DEFINITION
let TweetType = new GraphQLObjectType({ name : 'Tweet', description :
'A tweet object', fields : () => ({ id : { type: GraphQLID }, created_at : { type: GraphQLString }, text : { type: GraphQLString }, retweet_count : { type: GraphQLInt }, }) }); DATA DEFINITION
let twitterType = new GraphQLObjectType({ name : 'TwitterAPI', description :
'The Twitter API', fields : { tweet: { type : TweetType, args : { id : { type : new GraphQLNonNull(GraphQLString), description : 'Unique ID of tweet' } } } } }); export const QueryObjectType = twitterType; DATA DEFINITION
let twitterType = new GraphQLObjectType({ name : 'TwitterAPI', description :
'The Twitter API', fields : { tweet: { type : TweetType, args : { id : { type : new GraphQLNonNull(GraphQLString), description : 'Unique ID of tweet' } }, // RESOLVER resolve: (_, { id: tweetId }) => YOUR DATA ACCESS CODE GOES HERE! } } }); export const QueryObjectType = twitterType DATA RESOLVER DEFINITION
let twitterType = new GraphQLObjectType({ name : 'TwitterAPI', description :
'The Twitter API', fields : { tweet: { type : TweetType, args : { id : { type : new GraphQLNonNull(GraphQLString), description : 'Unique ID of tweet' } }, // RESOLVER resolve: (_, { id: tweetId }) => twitter.getTweet(tweetId) } } }); export const QueryObjectType = twitterType; DATA RESOLVER DEFINITION
let TweetType = new GraphQLObjectType({ name : 'Tweet', description :
'A tweet object', fields : () => ({ id : { type: GraphQLID }, created_at : { type: GraphQLString }, text : { type: GraphQLString }, retweet_count : { type: GraphQLInt }, }) }); DATA DEFINITION
let TweetType = new GraphQLObjectType({ name : 'Tweet', description :
'A tweet object', fields : () => ({ id : { type: GraphQLID }, created_at : { type: GraphQLString }, text : { type: GraphQLString }, retweet_count : { type: GraphQLInt }, retweets : { type : new GraphQLList(RetweetType), description : 'Get a list of retweets', args : { limit: { type : GraphQLInt, defaultValue : 5 } }, // RESOLVER resolve: ({ id_str: tweetId }, { limit }) => YOUR DATA ACCESS CODE GOES HERE! } }) }); DATA RESOLVER DEFINITION
{ twitter { tweet(id: "1134427651672875008") { text, created_at, user {
screen_name, tweets(limit: 2) { retweets(limit: 2) { user { name } } } } } } } { "data": { "twitter": { "tweet": { "text": "IT'S @daycamp4devs DAY! :) \\o/ \\o/ \\o/ \\o/ \\o/ https://t.co/RrTFHQKUNt”, "created_at": "Fri May 31 11:53:23 +0000 2019”, "user": { "screen_name": "CalEvans", "tweets": [ { "retweets": [ { "user": { "name": "Eric Hogue" } }, { „user": { "name": "Cristiano D. Silva" } } ] }, { "retweets": [] } ] } } } } } REQUEST RESPONSE
Execution performance
req resp CLIENT SERVER /graphql?q=… GRAPHQL
req resp CLIENT SERVER GRAPHQL DATA STORAGE 1 REQUEST N+M
QUERIES? /graphql?q=…
Cache and batch your data, Even in request scope
None
var DataLoader = require('dataloader') var tweetLoader = new DataLoader(keys =>
batchedTweetKeys(tweetKeys)); var userLoader = new DataLoader(keys => batchedUserKeys(usersKeys)); tweetLoader.load(tweetId) .then(user => userLoader.load(user.id) .then(retweeted_to => tweetLoader.load(retweeted_to.id) DATALOADER DEFINITION
let TweetType = new GraphQLObjectType({ name : 'Tweet', description :
'A tweet object', fields : () => ({ id : { type: GraphQLID }, created_at : { type: GraphQLString }, text : { type: GraphQLString }, retweet_count : { type: GraphQLInt }, retweets : { type : new GraphQLList(RetweetType), description : 'Get a list of retweets', args : { limit: { type : GraphQLInt, defaultValue : 5 } }, resolve: ({ id_str: tweetId }, { limit }) => dbTeetLoader.load([ 'SELECT tweetId FROM retweets WHERE originalTweetId=? LIMIT ?', tweetId, limit ]).then(rows => rows.map(row => tweetLoader.load(row.tweetId))) } }) }); DATALOADER DEFINITION
Schema synchronization
Other use cases? ]
https://labs.getninjas.com.br/sharing-data-in-a-microservices-architecture-using-graphql
Kubernetes API gateway GRAPHQL server on top of gloo and
envoy
$> sqoopctl install kube SAMPLE CONFIGURATION
$> sqoopctl install kube $> kubectl apply -f PATH_TO_CONFIG/tweets.yaml SAMPLE
CONFIGURATION
$> sqoopctl install kube $> kubectl apply -f PATH_TO_CONFIG/tweets.yaml $>
glooctl get upstream +--------------------------------+------------+----------+-------------+ | NAME | TYPE | STATUS | FUNCTION | +--------------------------------+------------+----------+-------------+ | gloo-tweets-8080 | kubernetes | Accepted | getTweet | +--------------------------------+------------+----------+-------------+ SAMPLE CONFIGURATION
$> kubectl get upstreams -n gloo-tweets-8080 -o yaml apiVersion: gloo.solo.io/v1
kind: Upstream metadata: // TRUNCATED spec: upstreamSpec: kube: selector: app: tweets serviceName: tweets serviceNamespace: gloo-system servicePort: 8080 serviceSpec: rest: transformations: getTweet: body: {} headers: :method: text: GET :path: text: /api/tweets/{{ default(id, "") }} content-length: text: "0" content-type: {} transfer-encoding: {} SAMPLE CONFIGURATION
$> sqoopctl schemat create tweets -f tweets.graphql $> sqoopctl resolvermap
register -u default-tweets-8080 -s tweets getTweet Query tweet SAMPLE CONFIGURATION
Where to look for more? ]
None
None
None
None
None
thanks @mariuszgil