Implementing GraphQL API Gateway in .NET 6 + Hot Chocolate v12 + Redis
Another one from the GraphQL series and in this one we are going to implement a GraphQL API Gateway following the Federated Schema approach.
If you are new to the world of GraphQL, you can check out my previous articles where I explain and implement the basics of GraphQL using .NET Core 3.1, Hot Chocolate v11, MongoDB and Docker.
Before we start
Let’s take a look at the two common approaches we have for distributed schema.
1. Schema Stitching
In the scenario of schema stitching, the configuration of the gateway schema is on the gateway itself. The gateway pulls the schema from the domain services and can be extended with SDL.
2. Federated Schema
In the federated approach, the schema are defined on the domain service. The domain services push the schema on a cache (like Redis). The gateway is subscribed to changes from this cache and can hot reload the schema if the configuration of a domain service changes. See more details here.
You can start developing from the Gateway or from the Domain Service, the advantage of starting with the Domain Service is that you can already see the result, that is, you can test the API and see if everything is as expected.
For these projects Redis is crucial, because the Domain Services are responsible for publishing their schema on Redis and the Gateway is responsible for getting the schemas that have been published and stitching them, exposing the complete graph in a single endpoint.
Domain Service A
The Catalog API is responsible for exposing the queries to list the products and brands and also publishing the schema to Redis.
We are using Code-first for this project, so the schema is automatically generated by Hot Chocolate when running the project.
CustomPublishSchemaDefinition is a custom extension I created to publish the schema to Redis via a toggle.
The toggle Stitching.Enabled can be turned off in the dev environment if you need to run without Redis dependency, however for this work as expected it needs to be true in the production environment.
If you want to organize your queries into different files (e.g by domain) you can use an ExtendedTypeObject annotation like I used to create QueryBrand.
Domain Service B
The Bag API is responsible for exposing queries to get the bag details and also exposing the mutation to add a new item to the bag.
AddToBagInput and AddToBagPayload are automatically generated by Hot Chocolate because we’re enabling mutation conventions in the Program class.
Note that we have a type with the same name (Product) in the Catalog and Bag APIs, but with different properties, by default Hot Chocolate adds a prefix with the schema name (e.g catalog_Product). We have to be careful because in some cases this may not work as expected, and a domain service may use an exposed type of another domain, causing confusion for the client who is going to consume the GraphQL API.
Similar to the Catalog API project, but we’re adding mutation types and conventions.
🏆 Gateway API
The Gateway API is responsible for handling stitching, merges and all the other configurations that involve all the domain services, so the Gateway gets the schemas from Redis and exposes the whole graph in a single endpoint.
In order for the Gateway API to communicate with the domain services, it is necessary to register an HttpClient (AddGraphQLServices extensions) for each one.
Note that I had to rename the Product type from the Catalog API because the automatic merge done by Hot Chocolate did not work as expected and the queries started to use the Product type defined in the Bag API.
👍 Thanks for reading it and I really hope it helps you in your GraphQL API Gateway development.
See you in the next article. 👌