Everyone who has worked with GraphQL knows just how powerful and flexible this API query language is. With Apollo Federation, implementing federated GraphQL in the context of microservices becomes easier than ever. Let’s take a closer look at this tool, complete with going through practical exercises and use cases.
The first principle of Principled GraphQL is “One Graph” – the rule which encourages the implementation of a single graph to maximize the value of GraphQL. This is immediately followed by “Federated Implementation”.
“Though there is only one graph, the implementation of that graph should be federated across multiple teams.”
With the use of Apollo Federation, we are able to create distributed architecture fueled by GraphQL. It is a single supergraph composed of a collection of subgraphs made with the help of a few GraphQL directives and some interesting libraries. This looks very promising. But first… let’s take a step back and go to the old days when all of the supergraph elements were part of a single massive entity.
Don’t get me wrong. I’m not going to go over proclaiming how the monolith approach is the source of all evil in the world. I don’t believe that each and every monolith application was built without a well-thought approach and that microservices are a silver bullet to every encountered problem.
If we are not able to build a clean code base with monolithic applications, microservices definitely will not solve our problems. Besides, introducing microservices to this kind of application will only bring more chaos and despair.
The rule of a single data graph is fairly easy to implement with a monolithic approach. The most important role of a backend developer is to make the frontend developer happy. And what can make them more happy than accessing whatever it is they need, and exactly what they need with the use of a single query?
The monolith has its place in the wild. However, it comes with some limitations. With the growth of the application, this approach is simply not good enough, and most of all (crucial), that is not something that the cool kid wants to hear about. This brings us to the world of microservices. Modularity is the key.
Each microservice is a well-crafted piece of machinery that exposes a set of specialized endpoints. One way to tackle them would be by direct client-to-microservice communication. The client application would talk with publicly exposed endpoints by microservices. Again, much like in the monolith architecture, this might be fine for some small applications. However, when we grow bigger, this is not good enough. That brings us to the API Gateway pattern.
The API Gateway
With this approach, microservices are not directly exposed to the client application. An additional level of indirections is introduced that lives between client and API.
With the use of API Gateway pattern, we can simplify the client. Now the place responsible for calling multiple services will shift from client to gateway. This will also reduce the client roundtrips. It is also the place where you might introduce user authentication. With that knowledge, we can transit smoothly to the Apollo Federation.
Supergraph and Subgraphs
Apollo Federation embraced the API Gateway pattern. One graph, a supergraph, is composed of subgraphs. Each service is responsible for creating a subgraph and the combined supergraph is exposed by API Gateway. The API Gateway serves as a single point of entry for client applications.
… and last but not least: an API Gateway.
Apollo provides us with a couple of useful libraries. @apollo/federation allows us to create federated graphs and subgraphs that make it possible to build a subgraph schema as shown in the code example. @apollo/gateway is the package that brings ApolloGateway to the scene. Finally, the Apollo also provides a handy CLI tool, rover, which is helpful for managing graphs.
Everything revolves around three main concepts:
- extending entities,
- reference resolvers.
What is an entity you might ask? Here is an simple example:
The only difference with a regular GraphQL is the @key directive. With that, we can uniquely identify our entity. The owner of this entity is a Posts service. That would not be very interesting if this was the only thing that we could do with the entity. It can be extended by other services. In our case, Comments service extends the Post entity by adding the keyword extend and marking an external field with the @external directive.
The last piece of the puzzle are reference resolvers, which every entity needs. That will help us to… resolve the entity.
The API Gateway
Two services alone are useless to us. As mentioned before, we should not communicate with them directly. We need an API Gateway. The example code is short and straightforward. The only part that needs explaining is the serviceList array. In our scenario, we define a list of services by its name, followed by the URL under which they are available. Under the hood, the Apollo gateway will generate a supergraph based on subgraphs fetchend from services.
How does everything look from the client’s perspective? We execute two queries with the use of Apollo Playground and fetch the list of all posts.
The first query only involves Posts Service:
The response contains only data from this service:
We can see that the data indeed was fetched only from Posts Service:
Now we add a comments section to our query:
Comment sections are available only with Comments Service. However, from the client’s perspective, it is completely irrelevant. The query is simple and all requested data is there.
When we look closer, we can see that there were two requests orchestrated by the Apollo Gateway. One to Posts Service and another to Comments Service.
The serviceList is very useful for local development or prototyping. However, it might not be suitable for production (and might be removed in future releases). We need a central registry that allows us to track our schema. One of the solutions might be to use ApolloStudio.
“There should be a single source of truth for registering and tracking the graph.”
If we look at the code, we will see that the services are running on:
Posts Service – http://localhost:5001.
Comments Service – http://localhost:5002.
To simplify things, we will introspect suphraphs with the use of rover cli and publish it to Apollo Studio.
Where <GRAPH_ID> needs to be replaced by your Graph ID and <API_KEY> by your API key from Apollo Studio.
If we want to use graphs from the registry instead of providing a serviceList array, the ApolloGateway class needs to be instantiated without any arguments. Furthermore, two environmental variables need to be provided.
Apollo Federation – summary
The Apollo Federation allows us to build distributed systems with a clean and declarative approach by using GraphQL. It is a nice piece of technology that is worth trying. Through Apollo, we are getting a lot of interesting tools that are fun to work with. Rover CLI can be integrated with CI/CD and we can provide our own solution for central registry. What’s more, Apollo gives us a full specification.
With that, you have a lot of reasons to try it out and all you need to make an informed choice about it!