Understanding federated GraphQL

By: David Boland

GraphQL federation is an API architecture that takes the best of both monolith APIs and microservices, providing a single endpoint for all your services.

Contentful

GraphQL

A Note before the post: This article was originally posted on Contentful's blog. I wrote it as a guest post as part of their writer's program. All the images in this post were created by them. Special thanks to their team for not just the images, but for also helping edit this post, and publishing it on their site.


In the past couple of years, content management has seen a shift in the way we architect our projects. More and more people are shifting away from monoliths and adopting more of a microservice architecture. If you are already using Contentful, you have already started to see the benefits of going the microservice route.

While microservices are a step in the right direction, they present a new set of technical challenges. When having any number of microservices, consumed by any number of channels, you can run into issues of scaling and maintenance.

GraphQL Federation has emerged as the answer to these technical hurdles. GraphQL Federation is an architecture that combines multiple schemas into a single endpoint.

The path towards federated architecture

To help better understand GraphQL Federation, it's helpful to review how we got to this point in API architecture.

We started out with our traditional monolith API. These APIs would contain multiple endpoints for accessing data across your organization.

graphql-monlith-api

For example, an ecommerce organization could have endpoints for data about products and customers. You might have endpoints for submitting forms and processing data during checkout. You might even have endpoints for backend services, such as managing product or customer data.

This is a lot to maintain. You would need a development team that has knowledge of all these different domains. Or at least how changes to one area might affect another. You share the same code base, which makes you less agile. Coordinating incremental or large feature changes across the domains can be a headache.

Microservices are the answer to these problems.

graphql-microservices

Microservices can solve all these problems presented by the monolith architecture. I won't go into detail about all the advantages of microservices over monolith architectures. Instead, I would suggest this article on Monolith vs Microservices for more information.

It's important to understand that the composability of microservices allows us to easily develop and scale our API. Adding/updating microservices can be done in their own silo without affecting other services.

As we started adopting microservices, we then transitioned to using an API gateway.

graphql-gateway

The API gateway is an attempt to take the best of both microservices and monolithic architectures. We still have our composable microservices in the backend. The gateway provides clients with a unified endpoint. It can also manage other services, like authentication or custom business logic.

Federation is the next step in architecture design. While the API gateway had its improvements over microservices, its unified endpoint still required domain-specific logic to bring all the services together. This is because the API gateway is not decoupled from the microservices they interact with. Federation improves on this by keeping that unified endpoint, while maintaining the decoupled and distributed architecture of microservices.

Key features of GraphQL Federation

Distributed architecture

Federation benefits from the distributed architecture that comes from using microservices. Microservices themselves are a form of distributed architecture, which is a design concept where the components of your application are broken up into separate services.

This ensures scalability, decoupling, and sometimes improved performance. Scalability is achieved through our ability to add new microservices and have them available immediately in our federated endpoint. Our ability to make updates to one service without worrying about affecting any other service ensures we keep things decoupled.

Federation accomplishes this distributed architecture by how it composes its unified schema from the schemas of each microservice.

Schema composition

Schema composition refers to the grouping of schemas across your distributed architecture into a single, unified schema.

Let's look at our ecommerce example again. Say the customer service department needs to look up a customer and check their order shipment status. Without federation, you would have to work with the following schemas:

# User Schema (Simplified)
type User {
  id: ID!
  firstName: String
  lastName: String
}

# Order Schema (Simplified)
type Order {
  id: ID!
  userId: ID!
  shipped: Boolean
  products: [Product]!
}

This unified schema is composed automatically from all the sub schemas. This allows us to maintain our decoupled architecture.

# Combined Schema (Simplified)
type User @key(fields: "id"){
  id: ID!
  firstName: String!
  lastName: String!
  orders: [Order]! @provides(fields: "id shipped")
}

type Order {
  id: ID!
  shipped: Boolean!
  products: [Product]! @provides(fields: "id name")
}

type Product @key(fields: "id") {
  sku: ID! @external
  name: String @external
  inStock: Boolean
  price: Int
}

Domain knowledge of how all these different services will interact is not required. Your channels only need to interact with one schema. The federation gateway knows how to route the requests to the appropriate service.

This is a simplified version of how these subgraphs would be combined. Additional routing data would be included to inform the gateway which subgraph to query.

Efficient data querying

With our composed schema, our federated gateway can intelligently query data. Based on that schema, queries are optimized and directed to their respective services.

graphql-federated-gateway

Based on the combined schema, requests can be routed by the gateway to the respective subgraphs. These queries can also be run in parallel to improve efficiency.

In addition to efficient querying, field-level caching and batched data loading are implemented. This improves overall performance and efficiency.

How to implement federated GraphQL

The good news is that backend developers can adopt a full federated services architecture regardless of their existing architecture. Whether you are working with a monolith or microservices, you can set up a federated gateway. Then you can work to incrementally decouple your monolith.

From here, I would recommend checking out Apollo GraphOS documentation on federation. They provide tutorials on how to get started with federation, as well as more in-depth technical details.

Considerations of GraphQL federation

As with any architectural design, there are things to consider before implementing. While we have made gains over the monolith architecture, we still have a single point of failure with our gateway.

Another aspect that you must consider is that with the addition of an API gateway layer, you could have a potential increase in latency. Each request must be taken by the gateway and routed to the appropriate service.

Conclusion

GraphQL Federation is an API architecture that takes the best of both monolith APIs and microservices. It provides a single endpoint for all your services, while maintaining a distributed architecture.

With federation, you get decoupled design, schema composition, and efficient data querying. Regardless of your existing architecture, you can start migrating to a federated architecture.

Make sure to check out the Apollo documentation or reach out on the Contentful Discord if you would like to find out more about GraphQL Federation.