GraphQL Microservices — C#. GraphQL API in a microservices…
By: Raphael Yoshiga
Tags: Programming, Dotnet, GraphQL, Software Development, Csharp

Photo by Nathana Rebouças on Unsplash

On my last post, I explained why you could consider using a GraphQL API instead of REST. I used the example of an order summary page, where a mobile application might have to make multiple HTTP requests to fetch all the data. Those were individual calls, as this was a microservice architecture:

Then I showed a monolith Graph example, which is not exactly a fair comparison:

The monolith Graph Service enabled us to expose a single schema for the mobile app:

How could we have this schema in microservices architecture?

Schema Stitching.

We can divide the schema into multiple services as:

Order Summary split by service

For making that split we need an entry point that will orchestrate the call between the services, we will call it Graph Stitcher.

A few key points:

The GraphStitcher defines a “stitched schema”, which is a combination of the schema of the other services.

Orders, profile and product are offering /graph endpoints, the Graph gateway is just delegating.

The GraphStitcher is more than an aggregator, it can also override/extend the schema.

C# — HotChocolate demo

This is a long setup, so if you want to follow along, here is the source code.

Before we go into setting up the Graph Stitcher, let’s make sure we are running the Customer Service. So at http://localhost:5000/playground, we should receive:

Customer Service schema example

Setup the stitcher

Add this to the Startup.cs of an empty .net core web application:

The important bits:

AddStitchedSchema — That’s how we tell where our schema is coming from remote services.

With the builder from AddStiched schema, we do “builder.AddSchemaFromHttp(graph.SchemaName)” tell the HotChocolate framework where to delegate calls to.

services.AddHttpClient — We add a named HTTP client, with the same name as the schema

A simple non-dynamic version:

With this, we should be able to proxy the requests into the Customer Service from the Graph Stitcher

GraphStitcher playground:

Graph Stitcher delegating the call to Customer service

Customer Schema with firstName, id, lastName and title

It works, but as you can see, Customer doesn’t have the field “orders” from the original schema.

Adding another schema:

As per the Startup.cs for the GraphSticher, we had a list of “graphProviders”, so if we add it to the list, the GraphSticher now should support order queries.

Graph Stitcher with Customer Service and Order Service schema

Still, we can query orders by customerId, but not access the orders directly from the customer object.

Extending the customer object

For adding orders to the customer object, we will need to extend the Customer type to add the “orders” property, and tell HotChocolate how to resolve it:

We just need to register the extensions to the schema with “AddExtensionsFromFile”, as:

And Voila! Customers now have a linking property to “orders”:

Stitcher now has “orders” in the Customer type

Just to remind you of our schema:

Linking products to order:items:

After adding products into the “graphProviders”, we will have to add an extension into the Item type:

But wouldn’t that mean there would be individual requests for each product?

product(id: 1)

product(id: 2)

At first sight, yes, but no. HotChocolate will brilliantly batch the requests to products(id: {productId}), by using aliases. Let’s say we are asking for two products:

Batching the database queries in the Product Service

Because the product service now receives the query with the aliases, we can make usage of Dataloaders to make sure we batch the requests and make a single database call:

And the final result:

GraphQL playground working from Stitcher with all services involved

References:

Design Considerations

I took the approach of the microservices not knowing about each other on the queries, but as an alternative, the services could query their dependencies directly as the GraphStitcher does.

For example, the profile service could have the property “orders” in the customer, but then suddenly Customer Service is offering the schema of orders. Then if we add Customer Service and the Orders Service into the Stitcher, the schema would be duplicated, it might break it might not.

Also consider that if services know about each other, they are dependencies that would have to be configured in a CI/CD pipeline.

Therefore I decided the Stitching way is a better way forward.

Conclusion

Photo by Joe Caione on Unsplash

If you are going for a GraphQL API, most likely you will want to use it in a microservices architecture, for that you will need a Graph Stitcher to combine multiple schemas.

Now with more experience in GraphQL, this thing is powerful, it allows the consumer a lot of flexibility and can make applications more efficient. But this flexibility is coming from good engineering practices, like usage of dictionaries, batching, etc, those practices are intermediate to advanced, so you need to keep in mind the learning curve and potentials for bad implementations.