skip to Main Content

I’m trying to wrap my head around GraphQL/Relay and I’m finding hard to get started on how to correctly setup a Relay compliant GraphQL API using Ruby on Rails.

I’ve found multiple tutorials on how to do this:

https://medium.com/react-weekly/relay-facebook-on-rails-8b4af2057152#.gd8p6tbwi

https://medium.com/@gauravtiwari/graphql-and-relay-on-rails-getting-started-955a49d251de#.m05xjvi82

But they all refer to a graphql-relay gem that doesn’t seem to be available at this moment: https://github.com/rmosolgo/graphql-relay-ruby

The grahql-ruby gem has a section in the documentation specific to relay, but I’m finding hard to understand what is needed to set this up to be consumed by a Relay client.

What is necessary to implement a GraphQL API for a Relay client in Rails?

2

Answers


  1. Chosen as BEST ANSWER

    I just want to leave here my findings for anyone who gets stuck with this in the future and wants to get pointed to a better direction.

    First, the graphql-ruby gem includes everything that is needed to implement a Relay compatible GraphQL API. In includes everything that was before in the graphql-relay gem.

    You need to provide 2 things in your Schema in order to make the Relay refetching feature to work well, an id_from_object method that converts an object in your domain, into a global id and also a object_from_id method that will decode the global id into an object in your application:

    ApplicationSchema = GraphQL::Schema.define do
      /* Create IDs by joining the type name & ID, then base64-encoding it */
      id_from_object ->(object, type_definition, query_ctx) {
        GraphQL::Schema::UniqueWithinType.encode(type_definition.name, object.id)
      }
    
      object_from_id ->(id, query_ctx) {
        type_name, object_id = GraphQL::Schema::UniqueWithinType.decode(id)
        # Now, based on `type_name` and `id`
        # find an object in your application 
        # This will give the user access to all records in your db
        # so you might want to restrict this properly
        Object.const_get(type_name).find(object_id)
      }
    end
    

    Also, all your types should implement the NodeInterface provided by the ruby gem, and expose a global_id_field instead of an ID type:

    PostType = GraphQL::ObjectType.define do
      name "Post"
      # Implements the "Node" interface for Relay
      interfaces [GraphQL::Relay::Node.interface]
      # exposes the  global id
      global_id_field :id
      field :name, types.String
    end
    

    This will allow Relay to refetch data like this:

    query {
      node(id: "RmFjdGlvbjox") {
        id
        ... on Post {
          name
        }
      }
    }
    

    Relay also uses a babel-relay-plugin which requires a schema.json to be generated and available to the client, if you're building an isolated API with no view rendering, the way to go is to let the clients fetch the schema and not to do that work in the server, something like apollo-codegen can work. However, if you are building a rails app and need the schema in the same app, then you can run an instrospection query and save the result to a json file using a rake task:

    Schema.execute GraphQL::Introspection::INTROSPECTION_QUERY
    

    Lastly, you'll need to understand that Relay expresses one-to-many relationships with connections:

    PostType = GraphQL::ObjectType.define do
      # default connection
      # obj.comments by default
      connection :comments, CommentType.connection_type
    
      # custom connection
      connection :featured_comments, CommentType.connection_type do
        resolve ->(post, args, ctx) {
          comments = post.comments.featured
    
          if args[:since]
            comments = comments.where("created_at >= ?", since)
          end
    
          comments
        }
      end
    end
    

    Connections support some arguments out of the box, you can use first, last, before and after in your connection queries:

    query {
      posts(first: 5) {
        edges {
          node {
            name
          }
        }
      }
    }
    

    All of this is documented in the Relay documentation so make sure you read it as well as the graphql-ruby documentation.


  2. have you tried installing it?

    vagrant$ bundle install
    Fetching gem metadata from https://rubygems.org/............
    Fetching version metadata from https://rubygems.org/...
    Fetching dependency metadata from https://rubygems.org/..
    Resolving dependencies...
    Installing graphql 0.19.4
    Using bundler 1.11.2
    Installing graphql-relay 0.12.0
    Bundle complete! 1 Gemfile dependency, 3 gems now installed.
    Use `bundle show [gemname]` to see where a bundled gem is installed.
    

    in Gemfile:

    gem 'graphql-relay'
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search