July 02, 2021
6 min Read
July 02, 2021
6 min Read
API, the acronym for Application Programming Interface, is a software intermediary that allows two applications to communicate with each other. That could be a server, a client, or an app talking to a server. The timeline below illustrates how it has evolved through the years, and it lays a great foundation of how the API can be built. REST remains a popular tool for building APIs. However, in 2012, Facebook wanted something different than REST, and that is when GraphQL (Graph Query Language) was introduced.
REST is a Representational State Transfer API, meaning that each resource has its own endpoint. Initially, it was a dissertation published by Roy Fielding in 2000 and popularized by companies like Twitter in 2006. REST is an architectural concept for network-based software. It has no official set of tools, no specification, does not particularly care if you use HTTP, AMQP, etc., and is designed to decouple an API from the client.
REST API sometimes requires Multiple Round Trips. This applies when we need to display some data which must be consumed from different endpoints, and consuming data from only one endpoint is not enough. The table below illustrates three endpoints:
|GET /users||List all users|
|GET /users/:id||Get the single user with id :id|
|GET /users/:id/projects||Get all projects of one user|
What if in a client app, we need to fetch projects related to that specific user and some tasks that may also be related to the project itself? Should the back-end team develop anything extra? There are the following possible ways to do that:
Over-fetching and Under-fetching. When there is a need to return too much data, the client app does not need all that data. Customers are not happy if they are required to download extra information they do not actually need. On the other hand, by reducing the level of information on a server, the problem of under-fetching can be experienced, and another extra endpoint and resource on a server to get that data is needed. The solution is: GET /users?fields=firstname,lastname.
Difficulty in creating versions and deprecating fields which are not necessary for the new releases. It is hard to maintain REST APIs when it grows over time, and different requirements are requested to support different versions of apps and multiple clients. So, usually, v1 is left as it is, and v2 is created with the newer data structure. With GraphQL, it could be done without version control. GraphQL only returns the explicitly requested data, so new capabilities can be added via new types and new fields on those types without creating a breaking change. This has led to a common practice of continuously avoiding breaking changes and serving a versionless API.
Non-predictable data. With REST it is unknown what data will be returned from the server, what fields, how many of them, etc. With GraphQL, the client asks for specific fields to be returned. It does not matter if it is a query or mutation – you are in control of what will be returned back.
GraphQL is a newer concept, released by Facebook publicly in 2015. GraphQL, as a new way of asking data from the server, is a query language, specification, and collection of tools designed to operate over a single endpoint via HTTP, optimizing for performance and flexibility.
This table compares GraphQL and REST as two approaches that build API. Talking in general terms, it cannot be considered an apple-to-apple comparison, but more like an orange-to-apple parallel since the REST is the conventional standard for planning APIs, and GraphQL is a query language that helps solve problems with APIs. However, they are both still fruits 🙂
The main difference here is that GraphQL is a client-driven language. It has the architecture where the front-end app decides what data to fetch and how much it has to be returned from the server. On REST, everything is designed on the server, so the server drives the architecture.
|A query language offering efficiency and flexibility for solving common problems when integrating APIs||An architectural style largely viewed as a conventional standard for designing APIs|
|Deployed over HTTP using a single endpoint that provided the full capabilities of the exposed service||Deployed over a set of URLs where each of them exposes a single resource|
|Uses a client-driven architecture||User a server-driven architecture|
|Lacks automatic caching mechanism||Uses caching automatically|
|NO API versioning||Supports multiple API versions|
|JSON representation only||Supports multiple data formats|
|Only a single tool is used predominantly for documentation: GraphiQL||Wide range of options for automated documentation, such as OpenAPI and API Blueprint|
|Complicates handling of HTTP status codes to identify errors||Uses HTTP status codes to identify errors easily|
There are three main reasons why we might want to consider using GraphQL instead of REST.
This is the breakdown of how the query is constructed. Three main parts are considered: 1) operation type, 2) operation endpoint, 3) requested fields.
Types. The data model in GraphQL is represented in types, which are strongly typed. There should be a 1-to-1 mapping between your models and GraphQL codes. You can think of this as a database table where the user table has the fields like id, first name, last name, email, projects. So, things to remember is that exclamation point saying that an identifier (id) cannot be nullable or, in other words, it has to be something there as it’s a required field.
Queries. Queries define what queries you can run on your GraphQL API. By convention, there should be a RootQuery, which contains all the existing queries. In the example, the comment here shows how it looks on the rest API. In parenthesis around brackets, we see an argument that has to be a unique identifier, and after a colon is the type user. It shows what has to be returned when we do this query, so it returns the user. The project query will return the project, the task query will turn the list of tasks, and so on.
Mutations. If queries are GET requests, mutations can be seen as POST | PATCH | PUT | DELETE requests that modify the data. The example includes mutations of “createUser”, “updateUser”, “removerUser”.
Input. UserInput type is a User type without the id and projects fields. Notice the keyword input instead of type. You can think of this as a form on a page where you need to enter some data and what kind of information needs to be entered to create that user profile.
Resolvers. The resolver function gives a specific set of instructions for converting the operations of GraphQL into data. It is basically a controller function, the logic of what has to be returned (resolvers for queries) when that query happens and the user asks for the data, and resolvers for mutation are used when the user seeks to update or delete the data.
Schema. With types, queries and mutations, we define the GraphQL schema, which is what the GraphQL endpoint exposes to the world.
Two main resources to step deeper into the GraphQL field:
The GraphQL server API can be used as a gateway to other microservices, talking directly to the database or other REST APIs. Thus, you could have multiple REST APIs, get that data and make it one single source of truth.
This article is inspired by front-end developer Gediminas Survila’s presentation on “GraphQL vs. REST: Which is the best for API Development?”