Home Pokégraph - Evolving querying with GraphQL - 2/3
Post
Cancel

Pokégraph - Evolving querying with GraphQL - 2/3


In the previous post, I introduced the project and my take on modeling it based on domain-driven design approach, more specifically covering the Pokegraph.Domain project and its components. Now we will continue the series focusing on the Pokegraph.Api project, and how I’m using GraphQL to fetch data from the database.


GraphQL and .NET


Created internally in 2012 by Facebook, but released to the public in 2015, GraphQL is an open-source data query language and a runtime, designed as a very flexible and fast alternative to REST. It is spreadly used for building web and mobile apps that require consuming a large amount of data in a less sprawling way than REST APIs, due to its nature based on returning what the client specifies in a single call.

It’s not my intent to detail each aspect of it here or to compare all the differences with REST. You will find tons of material out there doing it. I’ll go for a straightforward but pragmatic implementation introducing the technology and the main concepts to the uninitiated ones. After that, it’s up to you to research the Pros and Cons of it. Although it’s a very versatile tool, it may not fit every case of need.

At the moment, there’s no official .NET implementation of GraphQL specification for .NET, but because GraphQL is a communication pattern, many projects flourished from the community to support it to many platforms, and it wasn’t different with .NET. One very popular package is GraphQL.NET, and because of its name, many developers tend to believe it’s part of .NET stack. Another, and newer project, which I’ve used in this project, is named HotChocolate. I don’t have enough experience with both to make a fair comparison, but it’s spread that this last is more flexible in many ways, so let’s dig into it a bit.

Hot Chocolate

You can install the HotChocolate package in your project with

1
dotnet add package HotChocolate.AspNetCore


This package comes with all we need to start hosting the runtime and using GraphQL. With a few steps in your Startup.cs like configuring the WebApplication to map the GraphQL endpoint and set some extension methods in the IServiceCollection container in order to register queries, mutations, subscriptions, and all the features you want to enable. I used a very minimal API, all the setup is done within the Program.cs file:

I have a post where I talked about minimal API on .NET 6. Check it out!

Banana Cake Pop

All ready to run, this package also includes a middleware named Banana Cake Pop that pops up a cool IDE on your browser to test the GraphQL server implementations.

Now all you need to do is hit the create document button and perform queries. The tool is handy enough to save all you do in the browser’s local storage; then you can continue it after the browser is closed. Another option is browsing the existing schema. With this project, it should look like this:


Schema and Queries and Subscriptions


By definition, the schema describes the shape of data the client can query from the API and what can be input to change it.

Notice that Banana Cake Pop has listed the query operations available I implemented in the Query.cs class:

One thing I liked about HotChocolate is that it can infer your GraphQL types automatically, so I didn’t have to create GraphQL types myself with the mapping for every field. Of course, it worked so smoothly because I mapped my complex domain objects into a very simple and flatten ViewModel with the help of Automapper. Otherwise, I would have to create a mapping type and enable it in the Program.cs with:

1
2
3
builder.Services
    .AddGraphQLServer()
    .AddType<YourType>();

Not exposing your domain objects directly to your API is good practice once it allows combining domain objects from different aggregates or the part that matters to be exposed. Also, it can prevent some serialization issues that may happen depending on the complexity of the object you’re returning and mainly avoid changes in your model (IT WILL HAPPEN!) affecting the consumer directly. As with any API you’re building, make sure you have control of everything you expose.

All Queries defined, let’s catch ‘Em All:

listPokemon

pokemonByNumber

You can see that we shape the results from the query, defining the fields we want in the order we want, and that flexibility makes GraphQL so cool!

Subscribing to events

Subscriptions are a very cool feature that use WebSockets to open channels the web client can subscribe and receive real-time notifications. (You can check a similar approach using SignalR in my other project).

All subscriptions are registered within this Subscription class:

Make sure to decorate the methods with the [Subscribe] attribute, and to define a [Topic(name)].


Testing subscriptions

Testing a subscription is simple. Let’s do it with the one that notifies when the listPokemon query is run:

subscription {
  onListedPokemon
}

You can see that when you hit the execute button, a spinner keeps spinning and the request never ends.

Now open another tab, which can be an incognito window or even another browser, to evidence the communication of what will happen, and we execute the intended query. The response then shows on the first window, returning the count of the list it was designed.


Last but not least, I enabled the subscriptions in the Program.cs:

1
2
3
builder.Services
    .AddSubscriptionType<Subscription>()
    .AddInMemorySubscriptions();


Mutations


Mutations allow us to add or change objects of a given Schema type. It’s fairly easy to use them, as seen from the Mutation.cs class below:

Like queries, I’m also subscribing to some events to notify when a Pokémon was inserted or updated into the catalog. Let’s then insert a pre-evolution of the known Pikachu with the following mutation:

The inputData param in the subscription comes directly from the input of PokemonData type argument in the InsertPokemon method, and it returned the PokemonViewModel that was just inserted. Then, running the subscription, check how the command is structured to query the fields we want after the insertion.

Notice you need to enable Mutations with the following extension method, setting your Mutation class.

1
2
builder.Services
    .AddMutationType<Mutation>();


Final thoughts


Implementing a GraphQL solution for the first time was straightforward using HotChocolate. I tried to stick with the basics I needed, but this library supports more advanced features I may need for another time and project.

In the upcoming article, I’ll focus on the construction of the single-page application based on Vue 3 with Composition API and Apollo.

See you there!


Check the project on GitHub



This post is licensed under CC BY 4.0 by the author.