GraphQL vs. REST

Junji Zhi
7 min readMay 18, 2019

--

People often talk about GraphQL like the next thing that will replace REST. That got me intrigued. I started researching and found a good article comparing the two.

Along the reading, I also found Roy Fielding, the person who coined the term REST, and started reading his dissertation. What surprises me is that, after nearly 20 years, many of his points are still relevant.

This article mostly comes from my notes about REST and GraphQL. I will compare the two in terms of component interface, data shapes, information hiding, and caching, and discuss how I conclude that GraphQL is dealing with a subset of problems of REST, and GraphQL cannot be seen as a simple replacement of REST.

General Interface vs. Flexible Data Shapes

From Fielding’s dissertation:

The central feature that distinguishes the REST architectural style from other network- based styles is its emphasis on a uniform interface between components (Figure 5–6). By applying the software engineering principle of generality to the component interface, the overall system architecture is simplified and the visibility of interactions is improved. Implementations are decoupled from the services they provide, which encourages independent evolvability. The trade-off, though, is that a uniform interface degrades efficiency, since information is transferred in a standardized form rather than one which is specific to an application’s needs. The REST interface is designed to be efficient for large-grain hypermedia data transfer, optimizing for the common case of the Web, but resulting in an interface that is not optimal for other forms of architectural interaction.

REST is optimized for large-grain hypermedia data transfer, which was thought of as the common case of the web. However, for APIs, a general interface as a REST design means inefficiency and rigidity.

An APIs often serve multiple clients, and clients have different needs. To satisfy all those needs, server side usually put all fields necessary into a REST response. If the response doesn’t have what the client wants, it needs another round trips to gather other data.

Because of this type of rigidity, REST clients may suffer under-fetching or over-fetching. This is a big issue for mobile apps because they care a lot about cellular data. They need just the right shape of data, and that’s where GraphQL shines.

How does GraphQL accomplish that?

GraphQL doesn’t use resource as an abstraction, so GraphQL doesn’t have the uniform component interface, as proposed in the REST dissertation above. By doing so, GraphQL gains efficiency.

In REST data can be fetched by the unit of a single resource, while in GraphQL, data can be fetched as a graph, and the shape of the graph is decided by API clients.

Can REST support graph-like data queries?

In practice, REST also supports a limited type of graph structured queries. Below is taken from a StackOverflow example:

/company/{companyid}/department/{departmentid}/employees

From a brief look, this API seems easy to understand: it enables us to query to employees under a certain department. But with a closer look, using this API means:

  1. we have to do two round trips to get the company and department ids before we can query the employees
  2. we can probably do the same thing with top level namespaces and query filters e.g., /employees?companyId=12 which is simpler.

It is advised against designing deeply nested URL like this. This example shows that REST is unfriendly about representing graph data in a native way.

Or, if we look at it another way, what REST says is we define all resources and their identifiers. When it comes to queries, REST is still in the model of one piece of resource at a time. This is by design. REST clients may pass query parameters to “influence” the shape of returned data. But the expressiveness is not comparable to GraphQL.

What information is revealed to API clients

The Fielding dissertation has interesting discussions about different designs of transferring data among Web components:

A distributed hypermedia architect has only three fundamental options: 1) render the data where it is located and send a fixed-format image to the recipient; 2) encapsulate the data with a rendering engine and send both to the recipient; or, 3) send the raw data to the recipient along with metadata that describes the data type, so that the recipient can choose their own rendering engine.

In the case of REST:

REST provides a hybrid of all three options by focusing on a shared understanding of data types with metadata, but limiting the scope of what is revealed to a standardized interface. REST components communicate by transferring a representation of a resource in a format matching one of an evolving set of standard data types, selected dynamically based on the capabilities or desires of the recipient and the nature of the resource.

According to the REST terminology, a representation is one form of a resource. The form can be an HTML document, a file or a JPEG image. REST allows multiple representations of the same resource.

The above quoted text talks about the different MIME types. These types are usually indicated in the HTTP content-type header. When a client sees a header value like image/jpegor text/html, it knows the what the type is the content is describing and processes the response accordingly.

The Web community agrees on a list of standard MIME types. A REST API only reveals this information to the clients, which is generic and doesn’t reveal more. This is to make sure the server doesn’t embed too much implementation details in the response. Once clients depend on those implementation details, the APIs are hard to obsolete and evolve. REST is aiming for long lived APIs that can last decades, so this is frowned upon from a REST standpoint.

GraphQL is heading towards that direction. It assumes that clients understand the GraphQL API docs and its query language. Arguably, this is the same (if not less) amount of effort to read up REST API docs.

What that means is that GraphQL API tells you more than the response MIME types, i.e., JSON. It also tells us, through another channel (i.e., GraphQL API documents), how the shape of the data looks like.

Because it violates REST’s HATEOAS standard, will GraphQL API last long?

I don’t have a definite answer. Lasting for decades long is not specified as one of the goals for GraphQL API. What I see so far is that, GraphQL entity is recommended to be modeled in terms of its business domains. It’s arguable that the core business domain is relatively stable. Once core business changes, APIs being obsolete may be just one of the lighter concerns among all others.

So what is GraphQL’s media type?

GraphQL only deals with one form: JSON. All the graph-like relationships are captured in JSON format.

What about other media types, like photos or videos? If we ask a GraphQL API: Can we send me a cat photo? A dump implementation may encode the image raw JPEG data in a JSON text. But what’s more likely to happen is a JSON with a field value as of a URL pointing to S3.

From this comparison, GraphQL narrows the problem down to how to define a query language to express what the clients want. The media types are already decided: JSON.

From REST’s standpoint, a GraphQL response is one representation of a resource. And REST covers the grounds that GraphQL doesn’t, so GraphQL cannot be a simple replacement of GraphQL.

Interestingly, official GraphQL doc recommends a new media type application/graphql:

If the “application/graphql” Content-Type header is present, treat the HTTP POST body contents as the GraphQL query string.

But this only applies to POST requests. GraphQL response is still of the JSON type.

Caching

This is where REST shines. Even the GraphQL doc admits that REST caching is easy. Being cacheable is one of the architectural constraints of REST.

REST caching happens in such a way: If a server wants to mark an REST API response as cacheable, it can indicate the intention in an HTTP header. Note that HTTP headers are visible to any proxies between the client and the server, so they can also cache a copy of the response and improve the overall network bandwidth and latency. Browsers usually treat all GET requests cacheable by using URL as the cache key.

There is no such built-in primitives in GraphQL. Clients have to rely on an global unique IDs, which is agreed upon between clients and servers in advance. Also there’s no fine-grained built-in control over which cached object has expired. So that’s another agreed-upon-in-advanced thing to consider if we want to implement GraphQL caching.

GraphQL GET vs. REST URI

Interestingly, GraphQL supports encoding the query in a GET request URL. The official documentation shows an example:

http://myapi/graphql?query={me{name}}

From the definition in Wikipedia, URI is defined as

URI = scheme:[//authority]path[?query][#fragment]

So a GraphQL GET URL is still a legit URI form, meaning that, from a REST standpoint, a GraphQL GET request is still requesting a resource. (A side-effect is that, if the query string is too long, we get a HTTP 414)

This seems like a design coincidence. After all, any GraphQL GET request can be re-written in the form of POST. So GraphQL can have advised implementers not to support GET at all.

This article covers a lot of grounds about REST and GraphQL. However, I felt that there is still much left to talk about what ideal APIs should be like, what design constraints they mean, and how GraphQL tries to achieve the balance of ideals and practical constraints. I’m curious how we feel about the current hype when we look back ten years from now.

Thanks for the reading!

--

--