The problem with the REST API
In the latest years, it was evident migration from the heavyweight SOAP APIs to the REST APIs. From an architectural point of view, we have evolved from a Remote Procedure Call style to a Resource-based approach. In REST, we talk about resources (NOUNS) that are exposed on the server-side and are consumed by the clients via HTTP CRUD methods (VERBS like GET, POST, PUT, DELETE). We are still talking about REST-full APIs and not fully REST APIs because some RCP style still has to coexist in REST. But REST is not Remote Procedure Call by definition. It is not like SOAP, where we call a remote method, and we are exchanging XML messages as parameters.
It is also clear that REST is the API of the moment (the year 2020). REST has a unique way to document the API with Open API. It also has an excellent way to secure it with Open ID Connect. There are a lot of tools to work with REST. But there is a problem with the REST that is part of its definition! It is about the isolation of the exposed resources.
According to the definition, the exposed REST resources are isolated and not linked in a graph on the server side then we will have to make many round trips to the server to get all the needed resources. We will be trapped in the 1+N problem when you need a REST resource mapped to a collection of other resources. Let’s say, for example, a catalog with multiple products. We will get the catalog resource with a call, and we will make a call to get the resources one by one. And this problem can explode when we have a complex UI that will oblige us to make a significant number of server calls and to assemble the responses on the client-side.
REST resources as graphs
On the contrary, if we model our REST resources as in DDD style with multiple aggregates each with a root aggregate on the server, we will need just one call to get the root aggregate, and we get all the required data. But in this case, we will get too much information. And this, because there is not a way to specify to REST how to filter the results. For example, we need just a call to get the catalog with all the products in a single JSON response.
This situation is often happening in modern applications, mainly when we use an ORM framework on the server-side, and we get an entire graph of entities from the database. The server entities are already mapped (OneToMany, OneToOne, ManyToMany), and for example, when we get the catalog from the database, this entity has inside all the products. And this graph of linked resources will be serialized as a huge JSON by the REST framework even if the collection is lazy-loaded by the ORM. And this problem can explode when we have a complex domain. And the companies are investing a lot of time to model a core domain in these days using techniques like DDD and TDD.
For this problem, we can try to find some solutions. We can use REST in a totally RPC fashion creating some endpoints that are methods to be called and passing the resources as messages. But in this case, we are contradicting the REST definition because we don’t have just simple resources accessed with CRUD operations.
We can create a different simplified package of resources than the database entities, but in this case, we will have to make all the transformations between the objects. We can try to hide some fields from the resources using some server-side tools but will invisible for all the REST calls we are making, and probably this is not desirable.
Introducing GraphQL
The REST problems are resolved elegantly by GraphQL. GraphQL assumes from the beginning that the data from the server-side is exposed as a rich data graph, not just a set of isolated resources like in the REST definition. And it specifies how to query this graph, filtering only the information that is needed. And get some specific trees from the big data graph as the responses of the queries. That’s why in GraphQL we have just one unique POST endpoint and not multiple isolated endpoints like in REST.
GraphQL offers a schema defined in Schema Definition Language (SDL) that is acting as a contract between the client and the GraphQL server, and it specifies the types of data exposed by the server and the queries that can be created by the client for this types. It is not important how we implement the server-side, but it’s true that we have to create some resolvers there. There are many options; the server can be an API Facade to some REST APIs, or wrap a relational database, or be an independent server-side standalone implementation of the graph.
Contrary to the REST assumption of isolated resources, the schemas are everywhere. For example, all the documents (XML, PDF, JSON), the file systems, the relational databases (even if it is a forced schema), HTML DOM, objects compositions, etc, can expose a schema. That’s how we store the majority of the data we have now. It’s true, there was a trend of schema-less databases (like Mongo where we have collections of semistructured data), but that model is applicable just in few situations.
GraphQL in 3 steps
Describe your queries and data types with SDL.
1article(2 author: StringQueryOperatorInput3 body: StringQueryOperatorInput4 children: NodeFilterListInput5 date: DateQueryOperatorInput6 excerpt: StringQueryOperatorInput7 hero: FileFilterInput8 id: StringQueryOperatorInput9 internal: InternalFilterInput10 parent: NodeFilterInput11 secret: BooleanQueryOperatorInput12 slug: StringQueryOperatorInput13 subscription: BooleanQueryOperatorInput14 timeToRead: IntQueryOperatorInput15 title: StringQueryOperatorInput16): Article17allArticle(18 filter: ArticleFilterInput19 limit: Int20 skip: Int21 sort: ArticleSortInput22): ArticleConnection!
Ask for what you want in form of queries.
1query MyQuery {2 allArticle(limit: 2) {3 edges {4 node {5 title6 date7 }8 }9 }10 }
Get predictable results in JSON format.
1{2 "data": {3 "allArticle": {4 "edges": [5 {6 "node": {7 "title": "GraphQL For The REST of Us",8 "date": "2020-01-01T00:00:00.000Z"9 }10 },11 {12 "node": {13 "title": "Awesome GraphQL",14 "date": "2020-01-02T00:00:00.000Z"15 }16 }17 ]18 }19 }20 }
Glossary of abbreviations
REST - REpresentational State Transfer | SOAP - Simple Object Access Protocol | API - Application Programming Interface | CRUD - Create, Read, Update, and Delete | HTTP - HyperText Transfer Protocol | RPC - Remote Procedure Call | JSON - JavaScript Object Notation | DDD - Domain Driven Design | TDD - Test Driven Development | DOM - Document Object Model | SDL - Schema Definition Language