In this post, we start with a brief introduction to GraphQL and its common industry accepted usage pattern as BFFs(Backends For Frontends). Can it be used beyond that? I would focus around the below questions
- What is GraphQL?
- Do I need to use GraphQL?
- Can GraphQL be used beyond Backends For Frontends(BFFs)?
Basic knowledge of REST is a prerequisite for understanding the concepts in this post.
What is GraphQL?
GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. So there are 2 components to this. A GraphQL server and a GraphQL client. Both of them talk to each other using GrpahQL query language. GraphQL is transport agnostic and works well over HTTP. The client sends a GraphQL query, the server understands what the client has asked it to do and process the request and sends the response. In the REST world, we all know what CRUD (Create, Read, Update, Delete) stands for and how it works. In the GraphQL world, the reads are Queries and the writes are Mutations. That's it 😊
History:
Facebook’s mobile apps have been powered by GraphQL since 2012. A GraphQL spec was open sourced in 2015.
Schema:
GraphQL has a Schema, which consists of Query (for read operations) and Mutation (for write operations) with it’s own type definitions.
schema {
query: Query
mutation: Mutation
}
Query:
Queries are used for read operations. Let’ take a simple example in the context of Facebook. A facebook user can log in and see multiple posts from their friends with a certain number of comments. An illustrative GraphQL type definition in this case may look something like this
type Query {
posts: [Post] # This query fetches list of Posts
... # Other query definitions
}type Post {
id: ID! # Id of the post
at: String! # Time at which it was Posted
caption: String! # Caption of the post
mediaUrl: String # Url to the image or video shared
location: String # Location of the post
comments: [Comment] # Comments on the post of type Comment
... # Other properties definition of a post
}type Comment {
id: ID! # Id of the comment
comment: String! # The text of the comment
at: String! # Time at which it was Commented
by: String! # The user who made the comment
... # Other properties definition of a Comment}
Sample GraphQL Query:
A sample query to fetch posts with comments for each post would look like the following
query {
posts {
id
at
caption
mediaUrl
location
comments {
id
comment
at
by
}
}
}
If you look at the above query, we only ask for the required fields and nothing more for the posts as well as the comments for each post. There could be more fields both for posts and comments, which we don't need and they are not part of the response as well.
Sample GraphQL Response
Here is a sample response for the above mentioned query. Notice the top level key is "data" followed by the query name which is "posts" in this case.
{
"data": {
"posts": [
{
"id": "some-uuid",
"at": "2020-07-26T16:10:57.076+0000",
"caption": "My latest post!!",
"mediaUrl": "http://somecdn/some-image.jpg",
"location": "Pune, India",
"comments": [
{
"id": "some-uuid",
"comment": "Wow, what a place!!",
"at": "2020-07-26T16:11:05.010+0000",
"by": "Mahesh"
},
{
"id": "some-uuid",
"comment": "I have been there too!",
"at": "2020-07-26T17:01:30.015+0000",
"by": "Neeta"
}
]
},
... // more posts in similar format
]
}
}
Sample GraphQL Error Response
In case of any error, the response would have a list of errors and the response would look something like this:
{
"errors": [
{
"errorType": "SomeException",
"message": "Some Error Message"
}
]
}
Mutation:
Mutations are used for write operations. Again, in the context of Facebook, an user can share posts, like posts, add comments, delete comments etc. So the type definition for the mutations may look something like this:
type Mutation {
sharePost(post: Post!): Post
likePost(post: Post!): Post
addComment(postId: ID!, comment: Comment): Comment
deleteComment(commentId: ID!): Comment
}
We won't cover examples for the Mutations here, but I would add URLs in the references section.
Do I need to use GraphQL?
GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.
GraphQL has been a popular choice for building Backends For Frontends(BFFs), where one needs to aggregate data from multiple data sources to be consumed by their various clients like Web Browsers on Mobile devices, Android App, iOS App, Web Browsers on Desktops/Laptops etc.
The data required for each of the client(Desktop, Laptop, Mobile) would vary based on the amount of data they can display based on display size of the device. We can create a BFF layer for each type of client or use something like GraphQL which allows the client to ask for exactly what it needs.
A picture is a worth thousand words. Let's add a few thousands 😉
BFF without GraphQL
In this case, all the communication happens using REST and each client has it'’s own BFF layer i.e. one for Web browser, one for Android, one for iOS etc.
BFF with GraphQL exposed to clients
Here the clients are GraphQL aware and they talk to the API using GraphQL. The GraphQL server talks to the microservices using REST.
One can very well have multiple GraphQL endpoints dedicated for a consumer i.e. you can still have separate GraphQL BFF for Web, Android, iOS etc. Would the duplication of Schema add value?
BFF with GraphQL working behind the scenes
In this case, we use GraphQL to aggregate the microservices apis but the clients still talk using REST. The clients are not aware of GraphQL and they need not make any change. The GraphQL server still talks to the microservices using REST.
In this case also, you can have multiple BFFs for each device and each talking to multiple GraphQL APIs behind the scenes
So do I really need GraphQL?
Based on your service clients (if they are internal i.e. a customer service portal, external i.e. a self service portal or an external business to business customer), who controls their source code and the confidence you have on GraphQL, you would fall in one of the above categories for your BFF implementation. If you are not already using GraphQL, give it a try and discover for yourself, if the trade-offs are worth it.
Can GraphQL be used beyond Backends For Frontends(BFFs)?
We know for sure, GraphQL can be helpful for BFFs but can it go beyond that. Let'’s see if we can use GraphQL for server-to-server communication.
GraphQL everywhere
In this case, you may still have an aggregator GraphQL API which can aggregate the GraphQL schema of multiple microservices and give you a Graph of your entire business model. The aggregator GraphQL server talks to the microservices using GraphQL instead of REST. The microservices also talk to each other using GraphQL.
As per Apollo, Appollo Federation is an answer to implementing GraphQL in a microservice architecture.
GraphQL and REST
You may have some clients where you can't force them to use GraphQL. So probably you would still have to use REST. Say you are going for GraphQL everywhere, even then, during the transition you may need to support both REST and GraphQL. Let'’s see how it looks
GraphQL for Reads and REST for writes
One of the possibility is to use GraphQL only for read operations (This is where GraphQL brings a lot of value). The write operations can still be REST. In someway this may look like CQRS working in 2 different protocols for Commands(REST) and Queries (GraphQL). In the world where everyone is making a move towards Serverless architectures, achieving something like this is not very difficult either. Now the real question, is this worth it?
Conclusion
There are more possible ways of using GraphQL for server to server communication, which is not covered here. At the moment, I have used GraphQL for a very limited server to server communication and like the power it brings. I'm considering to go for GraphQL for READ (within the microservices as well) and still use REST for WRITE. I would like to hear your feedback. Have you have taken this route? Have you successfully used GraphQL beyond BFFs?
References
- REST (Martin Fowler)
- GraphQL
- GraphQL Mutations
- Backends For Frontends (Phil Calçado)
- Backends For Frontends (Sam Newman)
- CQRS (Martin Fowler)
- Appollo Federation