A majority of web sites are SPAs, built either with Angular, Vue, React or any other framework. My personal preference is Angular but this is not the case of this topic :)
Apart from the web sites, a lot of mobile applications are hybrid built with frameworks such as Ionic.
All of them require a back-end system that handles the database calls, the heavy data processing/manipulation etc. How does the Client app (SPA or hybrid) communicates with the Server App (back-end)? I bet that the first thing that arises in your mind is the REST. And yup! You are right. This is not the only solution though. There are other solutions that you should consider.
From the title of this post, you can imagine what the solution I am talking about is :). GraphQL.
Let's see what this is and how we can use it.
Server Communication - REST
When you have to build a REST API, you know that you have to respect the REST principles and implement certain verbs.
The POST is responsible to Create data in the data-store.
The PUT is responsible to Update/Replace data in the data-store.
The PATCH is responsible to Update/Modify data in the data-store.
The DELETE is responsible to Delete data in the data-store.
If we had to categorize them, wouldn't it be safe to set them under Query and Mutate categories?
Well yes :) it would be safe. (glad you agree!)
Under Query we would have the GET verb and
under Mutate we would have the POST, PUT, PATCH, DELETE verbs.
Think of it. When we perform a GET request, we query the data from the data-store. Whereas, we mutate the data for all the other verbs.
Server Communication - GraphQL
Having categorized the REST verbs under Query and Mutate let's see the two basic factors of GraphQL.
Queries and Mutations. I am sure you got it. Right? You can imagine what each one is responsible for. We will see more soon...
For the communication between the Front-End(client) and the Back-End(server) we need to have a contract. We need to have a schema. I use the term "payload" for this.
For the sake of this post we will use the following JSON structure
In order to built this payload, we need to have the relevant objects/classes as well.
(the code is in TS)
When REST have payloads, the GraphQL have the Types. In order to depict the above payload in Types we have to have the following
This notation it looks like JSON. But it's not. It's a GraphQL SDL (Schema Definition Language) which consists of Type and Fields (it has much more but we won't cover them here. We will see just the very basics)
In front of Project and Task we see the keyword type.
The field is consist of a name and a "data" type. "id: ID"
In GraphQL the data types are called scalar types. That's why I have the term data in quotes. The built-in scalar types are
Note that with exclamation mark (!) we set the required fields
How can the Client request for Projects from the Server? We have to implement the relevant endpoints
GET → /projects
POST → /projects
PUT → /projects/:id
DELETE → /projects/:id
PATCH → /projects/:id
Say, that we need to get the tasks of a specific project. We need to implement a sub-resource/endpoint
GET → /projects/:id/tasks
(and all other verbs)
What if we want to get only that tasks though? Oh yes! We have to implement another endpoint
GET → /tasks
(and all other verbs)
The REST implementation have the endpoints, whereas the GraphQL have the Resolvers.
In order to follow the comparison between REST and GraphQL, think of Resolvers sort of what the controllers are in REST.
The communication between the Client and the Server is made only via one endpoint. I am using the Apollo Framework and by default this exposes the /graphql endpoint.
Having said that, how can the Client requests for Projects from the Server?
QUERY → /graphql
MUTATION → /graphql
Two major questions came in the surface!
The Client is responsible to query the data from the Server. And can change the query any time without having to change anything on the Server!
This is a legit query and we are asking for the fields "id" and "name" from the "Project", we ask for the relevant "Tasks" each "Project" has and we want to get only the "name" of each "Task". If we want more or less fields, we can do so
The second query won't return any Task and won't even send a query to DB. Cool ehh?
GraphQL Resolvers - Implementation
Let's see an implementation of the resolvers
By convention the Resolvers should be written under Query, Mutation or by scalar types. We can see here that we have Query.projects and Project.tasks
As I said earlier, the Resolvers are sort of the same with Controllers.
The Queries are associated with the Resolvers
In this example, the Query.projects executes a query to DB via mongoose and returns all the items. if you scroll up a bit, you will see that we have the name projects in the query. That projects is associated with the Query.projects.
The Client is responsible for WHAT
GraphQL query and the response
So far so good. What is the response of the query? No more than a simple JSON
Why is it called GraphQL? Where is the graph?
You might say that there is no reason to go with GraphQL as it seems to do similar things as REST does. Well, yes and no. In REST we can not query from the client and if we have a demanded view on the client side, we might need to send multiple requests to the server via REST. Multiple requests means roundtrips which is translated with performance issues.
The solution for the demanded view in GraphQL, is to built a graph and request what the client requires via a single request.
We asked for the "name" and "id" of a particular "Project", the fields "id" and "name" of the relevant "Tasks" and then we want to get the "Projects" that are associated with each "Task" and the "Tasks" that are associated with each "Project".
This seems to be an exaggeration! Think that the response of the GraphQL is the view model of the client. As such, you can do your bindings without having a middle layer to manipulate the data and the schema
Problems and solutions
Problem: Multiple round-trips to server to get the data needed for the Client
Solution: Get all the data via a single query and have only one round-trip
Problem: The data transferred in the wire are way more than required
Solution: The Client decides what data is required and not the server
Problem: The server Serializes way more data than required
Solution: The Client decides what data is required and hence the Serialization time is decreased
The GraphQL is relatively new to me. I hope I managed to help you understand the very basic concepts. As everything, requires study and experimentation.
Each implementation have its cons and pros. The GraphQL seems to be very promising and there are very nice frameworks out there. It is not a panacea though!
If you have any question, please shoot it. I will be happy to try answer it for you