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
Designing and implementing GraphQL API
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Mariusz Gil
May 31, 2019
Programming
110
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
320
Game of Developer Life... Deconstructed
mariuszgil
1
200
Back to forgotten roots
mariuszgil
1
440
Go micro with microservices
mariuszgil
5
710
Machine Learning for the rescue
mariuszgil
0
460
Discovering graph structures
mariuszgil
3
560
Introduction to Aerospike with PHP
mariuszgil
8
880
Processing events at scale
mariuszgil
2
400
Other Decks in Programming
See All in Programming
AI Readyの正体はデータマネジメントだ メダリオン2.0の最前線
freee
PRO
0
190
What's New in Android 2026
veronikapj
0
260
PHP に部分適用が来るぞ!……ところで何それ?おいしいの? #phpcon / phpcon-2026
shogogg
0
630
ITヒヤリハットを整理してみた ~ライフサイクルと原因から考える再発防止策~
koukimiura
1
140
変わらないものが、変わるものを決める — 意図駆動開発 × イベントソーシング × イミュータブル | What Doesn't Change Decides What Can — IDD × Event Sourcing × Immutability
tomohisa
0
1.5k
楽しそうなつよつよエンジニアと目が死んでる僕/A brilliant engineer having a blast, and dead-eyed me.
3l4l5
2
110
Android CLI
fornewid
0
220
OpenSpecのproposalにbrainstormingを持たせてみた
tigertora7571
1
220
「人を評価する AI」の設計と実装
ryoyanara
0
190
全PRの83%がAIレビューだけでマージできるようになった開発組織はその後どうなったか
athug
1
1.6k
AI Nativeにデータを扱うための組織・基盤のこれまでとこれから
kirimaru
0
110
FDEが実現するAI駆動経営の現在地
gonta
2
280
Featured
See All Featured
How GitHub (no longer) Works
holman
316
150k
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
330
Everyday Curiosity
cassininazir
0
270
Git: the NoSQL Database
bkeepers
PRO
432
67k
The Language of Interfaces
destraynor
162
27k
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
0
370
Prompt Engineering for Job Search
mfonobong
0
400
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
380
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
200
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
Chasing Engaging Ingredients in Design
codingconduct
0
260
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.8k
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