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
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
200
Back to forgotten roots
mariuszgil
1
440
Go micro with microservices
mariuszgil
5
720
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
KotlinConf Extended South Korea 2026 Keynote
l2hyunwoo
0
120
typoなんかねぇよ
raspython3
0
330
Claude Code全社展開のためにやったことn選~プラグイン302個・コミッター271人を支えるために~
kenchan
5
1.6k
AIに既存システムを理解させる技術 ~レガシーを見捨てないハーネスエンジニアリング入門~
ochtum
0
120
React本体のコードリーディング
high_g_engineer
1
150
自動化したのに回らない テスト運用の壁―AI時代の品質責任と生産性
mfunaki
0
390
運用ダッシュボードの設計を誰も教えてくれないのだけどみなさんどうしてるんですか? - チームに監視するという文化を根付かせるための第一歩を踏みたい -
satoshi256kbyte
1
140
書籍「プロフェッショナルAI駆動開発」紹介スライド
juntaromatsumoto
0
280
これって Effect でできたのでは? / TSKaigi Mashup Kansai #2
susisu
0
250
ソフトウェアエンジニアにとっての生成AI - 特性を知って使い倒す / generative ai for software enginner
kishida
7
2.1k
Pythonの実行はどこまで賢くなったのか? CPythonとPyPyから見る最適化のしくみ
curekoshimizu
3
1.4k
不幸な GC
chencmd
0
560
Featured
See All Featured
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.5k
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
480
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
Amusing Abliteration
ianozsvald
1
260
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
400
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
470
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
AI Search: Where Are We & What Can We Do About It?
aleyda
0
7.8k
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.8k
Joys of Absence: A Defence of Solitary Play
codingconduct
1
440
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
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