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
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
学びを記事・スライド・Xへ高速展開する― AI-assisted Learning Loopで回すコンテンツ生成術
ochtum
0
120
Groovy as a human and AI friendly programming language
paulk
0
110
IBM Bob でAI駆動開発『QC-Playbook』
ichirokano2
0
120
AWSに止められる覚悟してますか?
morizo_1984
2
550
golang-bob.pdf
iwatsukayura
0
140
AI-Powered Domain-Driven Design
ziobrando
0
290
PumaからFalconに移行したRailsアプリケーションでの実践
falcon8823
0
200
contenteditable と日本語入力に向き合う
colorful12
0
210
個人開発者よ、Honoを使え(おじさんver)
tanahiro2010
2
270
re:Inventに行く前に知っておきたい現地参加のノウハウ
nokomoro3
0
460
【加筆修正版】Laravel のアプリケーションをどこにデプロイするか #phpcon_ehime
akase244
0
160
Event is what happens
moro
2
1.3k
Featured
See All Featured
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.4k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
450
30 Presentation Tips
portentint
PRO
1
440
Measuring & Analyzing Core Web Vitals
bluesmoon
9
1k
A Modern Web Designer's Workflow
chriscoyier
699
190k
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
440
Amusing Abliteration
ianozsvald
1
350
Getting science done with accelerated Python computing platforms
jacobtomlinson
2
540
Keith and Marios Guide to Fast Websites
keithpitt
413
23k
The Invisible Side of Design
smashingmag
301
52k
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
740
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