GraphQL vs REST: which API is best for your web app?
At the moment of designing and developing a web service that will be used by our app, we need to think about the architecture we want to use.
Over the last years, REST has been a widely used API design. But in 2015, Facebook released GraphQL to the public, a query language for APIs, and it became an alternative to REST. The two approaches have a different way of working, and clients will have to implement a certain type of communication, based on the architecture used on the server. Let's talk about both approaches, the differences between them, and which one best suits our project.
An API (Application Programming Interface) is a group of protocols and definitions used to integrate different components of a system. It defines a contract between a "provider" and a "consumer", and all the parameters involved in the communication between them:
- The requests to be made.
- How to make them.
- The different responses.
- Data types.
With an API we can reuse existing services from other components of our app, with an abstraction layer over the details of how those services are implemented.
REST (Representational State Transfer) is a group of architecture principles followed to create web services that work using the HTTP protocol. These principles are:
- Client-Server: APIs should be designed with an architecture where the client and the server are decoupled. The client doesn't need to know implementation details from the server. This is helpful if we want to use the same server across multiple clients.
- Stateless: Each API request coming from the client must include all the information related to it, as it is independent of other requests. No context or session is stored in the server.
- Cacheable: Response data should be cacheable. Using a cache system gives the possibility to reuse responses from an endpoint for repeated HTTP requests and optimize interactions between client and server.
- Uniform Interface: Simplify the architecture by defining a uniform interface for all the interactions between client and server. To do this we have to accomplish the following conditions:
- Resources should be identifiable and independent of the representation sent to the client. Each resource must have a URI (Uniform Resource Identifier).
- The client should be able to manipulate the resources through representations, as they contain enough information to allow this.
- Self-descriptive messages sent to the client should contain all the information needed to process them.
- It should implement Hypermedia as the Engine of Application State (HATEOAS), so any client accessing a resource should be able to know all the available actions at the moment.
- Layered System: An architecture with hierarchical layers, to get better performance, security, and scalability.
- Code On Demand (optional): The server can send executable code to extend client functionality.
A RESTful API is an interface that accomplishes all the previously listed principles.
Information is grouped and distributed in resources. Every resource has its uniform resource identifier (URI). The server that manages these resources creates representations of them that are sent to the client. The client will operate with the API through these representations. A resource representation consists of metadata, information, and hypermedia.
The client doesn't need to know which technology was used to develop the server, since the behavior is encapsulated. That makes the implementation of the client easier, and independent of the technologies used by the server. The only thing that matters is the format of the request and response (usually JSON or XML), so the client knows how to handle the messages and information coming from the server.
To operate with the resources we use resource methods. They are normally associated with HTTP verbs (GET/POST/PUT/DELETE), even though they are not the same.
There is no established standard for REST APIs. That is one of the reasons why there are APIs presented as RESTful that don't follow the original principles.
- REST is the industry standard. It has the most mature developer tooling and has been around since Roy Fielding presented it in 2000.
- REST APIs use HTTP methods, making the implementation predictable for the client.
- REST APIs support various data formats (XML, JSON, HTML, plain text, etc.).
- REST allows data to be cacheable, which might improve performance and scalability.
- As the representation is defined by the server, it's complicated to customize the requests and bring only specific data. This can cause over-fetching: bringing data that we don't need.
- All the requests return one resource representation from a unique source.
- Generally, we need multiple round trips to get all the needed data.
- Public APIs where we want to determine what to expose to the clients.
- Simple applications that we don't want to overcomplicate.
GraphQL is a query language for APIs, with a syntax that describes how to request data. It is also the runtime executed in the server to process the queries. It operates over a unique endpoint using the HTTP protocol. It has some main characteristics:
- A type system is used to define and describe the data.
- The client specifies exactly the data that it needs.
- Multiple data sources can be queried in the same request.
- GraphQL follows the relationship between objects, hierarchically. The data returned to the client follows a graph structure.
- It isn't tied to any storage engine, allowing the GraphQL server to manage the data with custom logic.
By using the type system it's easier to validate if a query is valid or not, before runtime. After the validation, the query is executed and the result is returned, normally as a JSON object.
GraphQL has an introspection system that allows an app to explore the schema definition and determine which queries are supported. This is also helpful in case we want to generate documentation about our GraphQL API.
There is an IDE called GraphiQL, which allows the user to explore a GraphQL API and build queries.
- One unique endpoint to query.
- No over-fetching or under-fetching: As the client is responsible to define the data requirements, it won't download more (or less) information than needed from the API.
- Query one or more resources in the same request. This will avoid making multiple API calls for an operation.
- Defining a type system and a GraphQL schema helps to understand what can be requested and returned from the server. After that, Frontend and Backend teams can work without depending on each other.
- Extending APIs and adding functionality wouldn't affect existing client GraphQL queries.
- A growing and maturing ecosystem of tooling.
- GraphQL uses a single endpoint and custom requests, so caching is complicated.
- Adding the support for custom queries to an API makes it more exposed to arbitrary requests.
- Only supports JSON representation for responses.
- GraphQL queries can become large. We have to specify everything we want to bring, and sometimes we are tempted to do a lot in one request.
- Applications where we usually need nested data to be fetched. i.e. blog posts with their comments and people details.
- APIs that will be consumed by mobile devices, smartwatches, etc., where we need to limit bandwidth usage.
- Apps that receive data from multiple APIs/sources. For example, bringing data from different analytics tools to display in a control panel.
- When we want to handle different microservices.
Sanity.io offers an open-source query language called GROQ (Graph-Relational Object Queries). It allows us to describe what information we want in our application, join data from different documents, and generate a response with only the information that is needed.
Let's say we want to retrieve data related to a movie from an API. This is how it will look like using a REST API:
GET http://test-api.com/movies/11
This will be using GraphQL:
http://test-api.com/movies/
query {
movie(id: 11) {
_id
title
releaseYear
}
}
And this is how a GROQ query looks like:
*[_id == 11]{
_id, title, releaseYear
}
After going through the features of REST and GraphQL APIs, and describing their similarities and differences, we can say that neither is better than the other. What we have to evaluate is the requirements of the project that we will develop, the clients that will connect to our API, and based on that determine which architecture fits better for our use case.
Sanity – build remarkable experiences at scale
Sanity Composable Content Cloud is the headless CMS that gives you (and your team) a content backend to drive websites and applications with modern tooling. It offers a real-time editing environment for content creators that’s easy to configure but designed to be customized with JavaScript and React when needed. With the hosted document store, you query content freely and easily integrate with any framework or data source to distribute and enrich content.
Sanity scales from weekend projects to enterprise needs and is used by companies like Puma, AT&T, Burger King, Tata, and Figma.