From REST to GraphQL: Why and How to Make the Move

REST is something of an industry standard for API design. It's simple, well-documented, and unobtrusive because it acts as a set of guidelines rather than as an enforced standard. This makes REST very easy to adopt. But the simplicity has trade-offs that have become more evident as the diversity of API clients has increased. GraphQL is the hot new kid on the block at the moment. But what are its benefits, and how do you make the move from REST?

The Pros of GraphQL

Different clients have different data requirements. Your clients don't just consist of Web and mobile anymore: there are voice-controlled interfaces, smart devices, and various developer platforms that don't necessary have a human interface. It can get increasingly complex for your API to cater to these different types of clients.

GraphQL turns the problem on its head. Instead of the server taking care of client data requirements, the client specifies the data requirements using a query language. Complexity moves from server to client.

1. Performing Complex Queries

One obvious area where REST falls short is the ability to perform complex queries. REST doesn't tell you anything about how to query your data, leaving it up to the developer to define. For instance, you may have an API that lists products and you want to filter them by name. You could use a query parameter to express that:

GET /products?name=Apple

But suppose you want to filter by multiple values (Apple OR Oranges). You may introduce a syntax like:

GET /products?name=Apple|Orange

Now, think of AND conditions or groups of conditions. A developer is pushed to invent her query syntax, specific to that API. GraphQL, as the name implies, is a query language, so it's pretty much designed for this purpose. Your clients need only to learn GraphQL to express all their data requirements.

2. Versioning

With REST, changing the field name or removing a field can mean a breaking change. This often requires deprecating the API while maintaining the previous version for clients still using it, at least for some time.

With GraphQL, you can add a new field without any fear. If you need to remove functionality, you can declare the field as deprecated, instead of removing it, and the deprecated field will continue to function. This gradual, backward-compatible process removes the need for incrementing version numbers.

3. Efficiency

In a typical RESTful API, fetching a set of related data means doing a new HTTP request. Suppose you want to fetch product 1 and all the reviews for that product. This would take two requests:

GET /products/1
GET /products/1/reviews

Unless you invent a syntax that tells the API to fetch reviews:

GET /products/1?include=reviews

GraphQL standardizes this by giving the ability to express hierarchy. There are other benefits too. Because GraphQL is a typed system, it has the ability to select fields you require in the response, leaving room for optimization. If a client doesn't need to query a piece of data, neither does the server, so it can do simpler queries and transfer less data.

What About Hypermedia?

You may argue that some of the issues above can be addressed with hypermedia, by linking to related URIs inside response. While hypermedia is useful for describing API capabilities on a resource level, it doesn't explain how to query data, as in defining search criteria or selecting fields for output. Similarly, deprecating parts of the API by having the hypermedia point to a different URI will work, but changes to a response, such as field rename, typically means breaking change, which requires version increase. Hypermedia and GraphQL solve different class of problems, with GraphQL being a way to express data requirements and hypermedia (as in HATEOAS) way to manipulate application state.

Moving to GraphQL

OK, suppose you're already sold on GraphQL and want to make the transition, how do you go about it?

Sticking to our previous example, we have an API that deals with products and reviews. Let's create a simple Rails app by typing the following into the Rails console:

rails new product-api --api

which has two models: Product and Review

rails g model Product name:string
rails g model Review content:text product:references

Products can have reviews, so in app/models/product.rb:

class Product < ApplicationRecord

 has_many :reviews

end

Controllers provide typical set CRUD operations, like:

class ProductsController < ApplicationController
 def index
   render json: Product.all
 end


 def show
   render json: Product.find(params[:id])
 end


 def create
   render json: Product.create(params[:product])
 end


 def update
   render json: Product.find(params[:id]).update(params[:product])
 end


 def destroy

   render json: Product.destroy(params[:id])
 end
end

And the route is:

resources :products

That's the standard RESTful API. You're able to create a new product by posting to/products:

curl localhost:3000/products -H 'Content-Type: application/json' -d'{"name": "Apple"}'

And you can query that data by doing:

curl localhost:3000/products


[{"id":1,"name":"Apple","created_at":"2017-02-12T13:19:40.519Z","updated_at":"2017-02-12T13:19:40.519Z"}]

 

The GraphQL Way

Now, let's create a GraphQL interface version of this API. Being a Rails app, your best option is to use the GraphQL-API framework for Rails.

Saša Branković Engineering Manager at Intercom. Thinks deeply about world of interconnected apps.
 

Comments