note, this doc is written by my co-worker Derric, but we blog at the same place.
Since being introduced by Facebook, GraphQL has taken the API world by storm as an alternative to REST APIs. GraphQL fixes many problems that API developers and users have found with RESTful architecture. However, it also introduces a new set of challenges which need to be evaluated. Because GraphQL is not simply a evolutionary replacement for RESTful APIs, this post will deep dive into the pros and cons of each and when GraphQL makes sense for your application.
History
Before RESTful APIs, we had RPC, SOAP, CORBA, and other less open protocols. Many pre-REST APIs required complex client libraries to serialize/deserialize the payload over the wire. A fundamental difference compared to today’s RESTful APIs, is that SOAP is strongly typed using formal contracts via WSDL (Web Services Description Language). This could wreck havoc on interoperability since even removing a 32-bit integer restriction to accepting a 64-bit long meant breaking upstream clients. SOAP is not an architecture, but a full protocol implementation consisting of security, error handling, ACID transactions, etc Some of the complexity is due to many abstraction layers baked into SOAP. For example, SOAP is able to run on HTTP, TCP, UDP, etc. While the protocol implementation afforded much abstraction, the application and data layer’s rigid contract between the client and server created a tight coupling between the two.
RESTful architecture was introduced in 2000 as a much simpler way to enable machine to machine communication using only the ubiquitous HTTP protocol without additional layers in a stateless and type free way. This enabled systems to be loosely coupled and more forgiving to contract changes between systems such as between companies.
REST today
REST APIs have become the de facto standard for companies deploying APIs and launching developer platforms. The beauty of REST is that a developer working with someone else’s API doesn’t need any special initialization or libraries. Requests can be simply sent via common software like cURL and web browsers.
REST uses the standard CRUD HTTP Verbs (GET, POST, PUT, DELETE) and leverages HTTP conventions and centered around data resources (HTTP URIs) rather than attempting to fight HTTP. Thus an e-commerce with a resourceapi.acmestore.com/items
can behave similar to a bank with a resourceapi.examplebank.com/deposits
. Both would probably need CRUD operations on that resource and prefer to cache queries (i.e. both GET api.acmestore.com/items
andGET api.examplebank.com/transactions
would be cached). 3rd party developers to a new API need to only reason about the data model and leave the rest to HTTP convention rather than digging deep into thousands of operations. In other words, REST is much tighter coupled to HTTP and CRUD compared to SOAP, but provides loose data contracts.
Problems with REST
As more variety of APIs are placed in production use and scaled to extreme levels, certain problems in RESTful architecture transpired. You could even say GraphQL is between SOAP and REST taking pieces from each.
Server driven selection
In RESTful APIs, the server creates the representation of a resource to be responded back to a client.
However, what if the client wants something specific such as return the names of friends of friends of a user where their job is engineer.
With REST, you might have something like:
GET api.example.com/users/123?include=friend.friend.name&friend.friend.ocupation=engineer
GraphQL allows you to represent this query in a cleaner way:
{
user(id: 123) {
friends {
friends(job: "engineer") {
name
}
}
}
}
Fetching multiple resources
One of the main benefits of GraphQL is to make APIs less chatty. Many of us have seen an API where we first have to GET /user
first and then fetch each friend individually viaGET /user/:id/friend/:id
endpoint, this can result in N+1 queries and is a well known performance issue in API and database queries. In other words, RESTful API calls are chained on the client before the final representation can be formed for display. GraphQL can reduce this by enabling the server to aggregate the data for the client in a single query.
More in depth analytics
While API analytics is also a negative for GraphQL apis since there is very little tooling out there. The tools that do support GraphQL APIs can provide much more insights into queries than RESTful APIs.
Problems with GraphQL
Caching
Caching is built into in the HTTP specification which RESTful APIs are able to leverage. GET vs POST semantics related to caching are well defined enabling browser caches, intermediate proxies, and server frameworks to follow. The following guidelines can be followed:
- GET requests can be cached
- GET requests can stay in browser history
- GET requests can be bookmarked
- GET requests are idempotent
GraphQL doesn’t follow the HTTP spec for caching and instead uses a single endpoint. Thus, it’s up to the developer to ensure caching is implemented correctly for non-mutable queries that can be cached. The correct key has to be used for the cache which may include inspecting the body contents.
While you can use tools like Relay or Dataloader that understands GraphQL semantics, that still doesn’t cover things like browser and mobile caching.
Diminishes shared nothing architecture
The beauty of RESTful APIs is that they complement shared nothing architecture well. For example, Moesif has a api.moesif.com/v1/search
endpoint and a api.moesif.com/v1/alerting
endpoint. Publicly, those two endpoints simply look like two different REST resources. Internally though, they point to two different microservices on isolated compute clusters. The search service is written in Scala and the alerting service is written in NodeJS. The complexity in routing HTTP requests via host or URL is much lower than inspecting a GraphQL query and performing multiple joins.
Exposed for arbitrary requests
While a main benefit of GraphQL is to enable clients to query for just the data they need, this can also be problematic especially for open APIs where an organization cannot control 3rd party client query behavior. Great care has to be taken to ensure GraphQL queries don’t result in expensive join queries that can bring down server performance or even DDoS the server. RESTful APIs can be constrained to match data model and indexing used.
Rigidness of queries
GraphQL removes the ability for custom query DSLs or side effect operations on top of an API. For example, the Elasticsearch API is RESTful, but also has a very powerful Elasticsearch DSL to perform advanced aggregations and metric calculations. Such aggregation queries may be harder to model within the GraphQL language.
Non existent monitoring
RESTful APIs have the benefit of following the HTTP spec with regards to resources just like a website. This enables many tools to probe a URL such as api.moesif.com/health
which would return 5xx if not OK. For GraphQL APIs, you may not be able to leverage such tools unless you support placing the query as a URL parameter as most ping tools don’t support HTTP and request bodies.
Besides ping services, there are very few SaaS or open source tools that support API analytics or deeper analysis of your API calls. Client errors are presented as a 200 OK in a GraphQL API. Existing tools that expect 400 errors will not work so you may miss errors happening on your API. Yet at the same time, more flexibility given to the client requires even more tools to catch and understand problems with your API.
Conclusion
GraphQL APIs can be exciting new technology, but it is important to understand the tradeoffs before making such architectural decisions. Some APIs such as those with very few entities and relationships across entities like analytics APIs may not be suited for GraphQL. Whereas applications with many different domain objects like e-commerce where you have items, users, orders, payments, and so on may be able to leverage GraphQL much more.
In fact, GraphQL vs REST is like comparing SQL technologies vs noSQL. There are certain applications where it makes sense to model complex entities in a SQL Db. Whereas other apps that only have “messages” as in high volume chat apps or analytics APIs where the only entity is an “event” may be more suited using something like Cassandra.
But at the same time, we expect the usage of GraphQL to continue rise, and the problems can be addressed with better tooling. For GraphQL, in-depth analytics make even more sense, check out our support for GraphQL at Moesif.
Top comments (11)
Very well explained, thanks for sharing!
very well put together post. Thanks for sharing.
There was so much explained to me in this post that I did not get elsewhere, after months of trying. Thank you so much @xngwng .
Regarding your section on "shared nothing", you are correct that as long as any API endpoint can be serviced by a single backend microservice, all you need is a gateway to route the incoming request to the correct service. However, as soon as you want an endpoint that pulls data from multiple microservices, it appears to me that REST isn't particularly helpful. You essentially have to handle the request in the gateway, which makes internal requests (REST, GraphQL, kafka, whatever) to the microservices. The gateway then has to compose the outgoing JSON which requires knowing about two internal APIs and one external one. With GraphQL, the notion of resolvers makes this somewhat easier.
Thanks for the nice and clean writeup!
A perfect clean wrap up of both technology, very impartial and meaningful. I can say I have a more clear idea of what to use when
I think Instagram is using GraphQL.? Can anyone analys the response of '?__a=1' and confirm.?
For example : instagram.com/jitheshkt/?__a=1
It only says "graphql" but you can't manipulate anything that it returns. Also I think it's not documented, so they change things with no notice. Recently my code broke because they changed something :(
Yes they do that often. Instagram doesn't entertain out of the API calls I believe. Even this particular response structure changed three or four days ago. Two of my production sites broken.
Are GET requests that so good? What turn me off about GET is character limits and it shouldn't have a body... (that is not suitable for relatively large JSON.)
When to use GET vs POST is NOT really related to the topic of GraphQL vs. REST.
Actually, check out this complete guide: moesif.com/blog/api-guide/api-desi...
There is a few articles regarding things to consider on when to use GET vs POST for designing APIs.