Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Designing and implementing GraphQL API

Designing and implementing GraphQL API

Mariusz Gil

May 31, 2019
Tweet

More Decks by Mariusz Gil

Other Decks in Programming

Transcript

  1. /tweets Resource GET PUT POST PATCH DELETE http method READ

    REPLACE CREATE MODIFY DELETE Action / crUD-style + =
  2. Main REST API pros Easy to understand Easy to document

    Easy to use Easy to implement Easy to scale Resources are disconnected from representations
  3. Main REST API cons Communication ping-pong Network heavy Time consuming

    … Communication ping-pong Network heavy Time consuming
  4. Graphql is query language for api With server runtime for

    processing queries Using defined type system
  5. 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! }
  6. 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! }
  7. 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] }
  8. 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 }
  9. 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 }
  10. 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 }
  11. 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 }
  12. interface Tweet { id: ID! created_at: String! text: String! user:

    User retweets: [Retweet] retweet_count: Int }
  13. 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 }
  14. { twitter { tweet(id: "1134427651672875008") { text } } }

    { "data": { "twitter": { "tweet": { "text": "IT'S @daycamp4devs DAY! :) \\o/ \\o/ \\o/ \\o/ \\o/ https://t.co/RrTFHQKUNt" } } } } REQUEST RESPONSE
  15. { 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
  16. { 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
  17. { 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
  18. 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
  19. 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
  20. 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
  21. 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
  22. 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
  23. 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
  24. { 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
  25. 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
  26. 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
  27. $> 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
  28. $> 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
  29. $> sqoopctl schemat create tweets -f tweets.graphql $> sqoopctl resolvermap

    register -u default-tweets-8080 -s tweets getTweet Query tweet SAMPLE CONFIGURATION