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 - Deccan RubyConf 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

August 12, 2017

More Decks by Shaiju Edakulangara

Other Decks in Technology

Transcript

  1. "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
  2. Client Server Updates a view Update endpoints Creates a new

    view New view version Create new endpoint
  3. 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
  4. 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
  5. 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 } } }
  6. 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" } } ] } } }
  7. 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
  8. query { users{ id name } post(id: 1){ title url

    published_at author{ name } comments{ body author{ name } } } }
  9. 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
  10. 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') } end field :comments, types[CommentType] field :author, UserType end
  11. 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
  12. 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
  13. POST /graphql curl -XPOST -d 'query= { post(id: 1) {

    title url } }' http://localhost:3000/graphql
  14. CommentType = GraphQL::ObjectType.define do name "Comment" field :id, types.Int field

    :body, types.String field :author, UserType do resolve -> (obj, args, ctx) { RecordLoader.for(User).load(obj.author_id) } end end
  15. malicious Query query { posts{ title url author{ name comments{

    author{ comments{ author { name comments{ author{ name comments{ author{ name comments{ body } } } } } } } } } } } }
  16. 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
  17. Client Server Hey, give me the resource with id =

    1 OK, here’s the resource with id = 1 In REST System
  18. Client Server Hey, give me the resource with id =

    2 OK, here’s the resource with id = 2 In REST System
  19. 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