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

Give REST a rest, use GraphQL for your next Rub...

Give REST a rest, use GraphQL for your next Ruby API - Jakarta RubyConf Indonesia 2017

GraphQL is a query language for APIs. While typical REST APIs require loading from multiple URLs, GraphQL APIs get all the data your app needs in a single request which makes Apps using GraphQL can be quick and stable

Avatar for Shaiju Edakulangara

Shaiju Edakulangara

October 07, 2017

More Decks by Shaiju Edakulangara

Other Decks in Technology

Transcript

  1. GIVE REST A REST, GRAPHQL FOR YOUR NEXT RUBY API

    GIVE REST A REST, GRAPHQL FOR YOUR NEXT RUBY API
  2. { name: 'Shaiju E', email: '[email protected]', tech_blog: 'tech.eshaiju.in', github: 'eshaiju',

    twitter: 'eshaiju', facebook: 'eshaiju', linkedin: 'eshaiju' }
  3. GET /comments/post_id=1 GET /comments/post_id=2 GET /comments/post_id=5 GET /posts GET /users/1

    GET /users/2 GET /users/5 Too many round trips! Client Server
  4. "post": { "id": 1, "title": "A GraphQL Server Implementation", "url":

    "http://tech.eshaiju.in/blog/2017/05/ "body": null, "votes": 100, "published_at": "11 Jul 2017 00 00 AM", "auther_name": "Shaiju E", "created_at": "2017-07-11 12:57:20 UTC", "updated_at": "2017-07-11 13:15:50 UTC" } "post": { "id": 1, "title": "A GraphQL Server Implementation", "url": "http://tech.eshaiju.in/blog/2017/05/06/a-graphql-server-implementation-r } What I get What I care about Over-fetching of data
  5. Client Server Updates a view Update endpoints Creates a new

    view New view version Create new endpoint
  6. Client Server Hey, give me the resource with id =

    1 OK, here’s the resource with id = 1 In REST System
  7. Client Server Here is everything you can do! (capabilities) I

    need that exact data shape (requirements) GraphQL OK, here’s the data with same shape
  8. What GraphQL is NOT It's not about graph databases and

    graph search It's not about data storage it's not language specific it's not a library
  9. What GraphQL IS GraphQL is a query language for APIs

    is a new API standard that provides an alternative to REST GraphQL Declarative data fetching - The client specifies what data shapes, and the server returns that data in exact same shape. GraphQL server only exposes a single endpoint and responds with precisely the data a client asked for
  10. query { post(id: 1){ title url published_at } } {

    "data": { "post": { "title": "A GraphQL Server Implementa "url": "http://tech.eshaiju.in/blog/2 "published_at": "2017-07-11 00:00:00 } } }
  11. query { users{ id name } post(id: 1){ title url

    published_at author{ name } comments{ body author{ name } } } } { "data": { "users": [ { "id": 1, "name": "Shaiju E" }, { "id": 2, "name": "Awin" } ], "post": { "title": "A GraphQL Server Implementation", "url": "http://tech.eshaiju.in/blog/2017/05/06/a-graphql-se "published_at": "11 Jul 2017 00 00 AM", "author": { "name": "Shaiju E" }, "comments": [ { "body": "Good post", "author": { "name": "Awin" } } ] } } }
  12. Mutations are the equivalent to the POST, PUT, PATCH and

    DELETE in HTTP/REST. mutation addComment{ addComment(input: { comment: "New comment", post_id: 1, author_id: 1}) { post{ id title comments{ body user{ name } } } } } Mutations are used to change your data Mutation
  13. query { users{ id name } post(id: 1){ title url

    published_at author{ name } comments{ body author{ name } } } }
  14. QueryType = GraphQL::ObjectType.define do name "Query" description "The query root

    of this schema" field :post do type PostType description "Find a Post by ID" argument :id, !types.ID resolve ->(obj, args, ctx) { Post.find_by_id(args[:id]) } end field :posts, types[PostType] do description "Return all posts" resolve ->(obj, args, ctx) { Post.all } end field :users, types[UserType] do description "Fetch all users" resolve ->(obj, args, ctx) { User.all } end end
  15. PostType = GraphQL::ObjectType.define do name "Post" description "Post and details"

    field :id, types.Int field :title, types.String do resolve -> (post, args, ctx) { post.title } end field :body, types.String field :url, types.String field :votes, types.Int field :published_at, types.String do resolve -> (post, args, ctx) { post.published_at.strftime('%d %b %Y %H %M %p') } deprecation_reason 'This field is deprecated' end field :comments, types[CommentType] field :author, UserType end
  16. CommentType = GraphQL::ObjectType.define do name "Comment" field :id, types.Int field

    :body, types.String field :author, UserType field :post, PostType end UserType = GraphQL::ObjectType.define do name "User" field :id, types.Int field :name, types.String field :joined_at end
  17. class GraphqlController < ApplicationController def execute variables = ensure_hash(params[:variables]) query

    = params[:query] context = { # Query context goes here, for example: current_user: current_user, } result = HackerNewsSchema.execute( query, variables: variables, context: context ) render json: result end end
  18. POST /graphql curl -XPOST -d 'query= { post(id: 1) {

    title url } }' http://localhost:3000/graphql
  19. { posts{ title url comments{ body author { name }

    } } } Know about N+1 Queries early
  20. malicious query query { posts{ title url author{ name comments{

    author{ comments{ author { name comments{ author{ name comments{ author{ name comments{ body } } } } } } } } } } } }
  21. Timeouts Solutions HackerNewsSchema.middleware << GraphQL::Schema::TimeoutMiddleware.new(max_seconds: 10) do |err, Rails.logger.info("GraphQL Timeout:

    #{query.query_string}") end Query Depth & Query Complexity MySchema = GraphQL::Schema.define do # ... max_depth 12 max_complexity 100 end