GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools. – http://graphql.org/
This guide will walk through installing and creating a GraphQL API in a Ruby on Rails application. It is a companion piece to the excellent Getting Started with Rails guide from RailsGuides. There are lots of resources that teach GraphQL-itself better than I can, so this guide just focuses on actually installing and using it in a Rails app.
Initial Schema
Let’s first verify that the schema of your app is what is expected for this guide. We will start off right were the RailsGuides guide leaves off. You should have articles and comments tables with the following schema:
Install GraphQL Gem
The GraphQL gem is located at https://rubygems.org/gems/graphql. Find the latest version of the gem, and add it to your Gemfile:
1 |
gem 'graphql', '~>1.7.1' |
Then run the graphql install command in your terminal:
1 |
> rails g graphql:install |
This should modify the Gemfile to add a development tool GraphiQL, created necessary files in the application, and add GraphQL routes to the route file.
Let’s do a quick status check to see if everything is working so far. Start the rails server, and visit the GraphiQL route, localhost:3000/graphiql.
You should see the GraphiQL user interface.
Adding Schema
Since GraphQL uses knowledge of relationships between types, we must first defined the types we will allow to be queries. In this case, Article and Comment. Add the following article and comment type files to /graphql/types
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# article_type.rb module Types ArticleType = GraphQL::ObjectType.define do name "Article" description "an article from the blog" field :id, !types.Int field :title, !types.String field :createdAt, !types.String, property: :created_at field :updatedAt, !types.String, property: :updated_at field :comments, types[Types::CommentType] end end |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# comment_type.rb module Types CommentType = GraphQL::ObjectType.define do name "Comment" description "a comment on an article" field :id, !types.Int field :commenter, !types.String field :body, !types.String field :createdAt, !types.String, property: :created_at field :updatedAt, !types.String, property: :updated_at end end |
These files define the schema and the relationship between Articles and Comments in a way that GraphQL can understand.
Adding Queries
Let’s add a article query to the api. Open /graphql/types/query_type.rb and add the following query below the :testField query:
1 2 3 4 5 6 7 |
field :article, Types::ArticleType do description "an article" argument :id, types.Int resolve ->(obj, args, ctx){ Article.find(args[:id]) } end |
You should now be able to execute a query against GraphQL using the Graphiql tool
Here is the text of the query for your copy+paste convenience:
1 2 3 4 5 6 7 8 |
query{ article(id: 1){ title, comments{ body } } } |
Adding a query to return all articles is just as simple. Add the following query type:
1 2 3 4 5 6 |
field :allArticles, types[Types::ArticleType] do description "an article" resolve ->(obj, args, ctx){ Article.all } end |
Using the endpoint
Up to this point we’ve used the GraphiQL tool to build and test our API. Let’s move to the actual graphql endpoint, located at /graphql
To test the endpoint you can use a tool like Postman to make requests to the app.
In postman, Let’s make a request to localhost:3000/graphql (remember to set the header Content-Type: application/json).
Set the request body to:
1 |
{"query":"query{\n allArticles{\n title\n }\n}","variables":null} |
In my case, the response is:
1 |
{"data":{"allArticles":[{"title":"hello world"},{"title":"My second article"}]}} |
Testing errors
Unless you’ve already configured your application differently, at this point it is likely that you will run into the error
1 |
ActionController::InvalidAuthenticityToken in GraphqlController#execute |
Rails, by default, will protect your application from a particular type security risk called a “cross-site request forgery”
A side-effect of this is that you cannot POST to the graphql endpoint unless we temporarily disable this feature, by modifying your application_controller to read:
1 2 3 |
class ApplicationController < ActionController::Base protect_from_forgery with: :null_session end |
Please note that this is an important feature, and should only be disabled during developments, or if you want to create a completely public api endpoint.
Wrapping up & Next Steps
At this point we have installed GraphQL into our Rails app, created schemas for Articles and Comments, and written query types to return that data from our application, as well as testing the real API endpoint using postman.
From here you can take any path to consume the data, such as through a front-end application like a React or Angular application, or exposing the endpoint publicly!
Some next steps may be: