Building and consuming GraphQL API in ASP.NET Core 5

GraphQL is a platform-independent, language-neutral query language and may be used to run queries and retrieve data. Joydip Kanjilal explains how to use GaphQI in an ASP.NET Core 5 app.

Since Roy Fielding coined REST in 2000, many applications have been built worldwide by adhering to the REST architectural constraints. REST has become widely popular primarily because of its simplicity and improved performance.

However, APIs today have become much more complex, and you need efficient data retrieval from a data store that might contain vast amounts of structured and unstructured data. Hence an alternative to REST was imperative.

Facebook chose to revamp its applications in 2012 to improve performance and efficiency. It was a time when Facebook’s mobile strategy didn’t work due to high network usage. While caching may have helped improve the app’s performance, the need of the hour was changing the data fetching strategy altogether. Here’s why GraphQL came in, and it has since grown in popularity by leaps and bounds within the development community.

GraphQL is a platform-independent, language-neutral query language that has been around for a while and may be used to run queries and retrieve data. GraphQL, like REST, is a standard that offers an easy and flexible method to query your data. GraphQL Foundation is now responsible for maintaining GraphQL.

This article talks about the characteristics and benefits of GraphQL before demonstrating how to use GraphQL with ASP.NET Core 5.

Pre-requisites

To work with the code examples illustrated in this article, you should have Visual Studio 2019 installed on your computer. If you don’t have a copy of it yet, you can grab one from here. If you don’t have .NET Core installed in your system, you can download a copy.

You can also find the complete code for the example in this article in GitHub repository.

What is GraphQL?

GraphQL is an open-source, flexible query language (“QL” stands for query language) for APIs, as well as a runtime for query execution on existing data. It was initially developed internally by Facebook in 2012 and then made public in 2015. GraphQL can make APIs more responsive, flexible, and developer friendly. It prioritizes providing clients with only the information they need. A REST alternative, GraphQL allows developers to create requests that pull data from multiple data sources in a single API call.

In GraphQL, you would typically send a declarative request in JSON format to get the data you need. The developer can define the requests and the responses using a strongly typed query language, enabling the application to determine what data it needs from an API.

One of the significant differences between REST and GraphQL is that the API determines the request and response in REST, whereas, in GraphQL, the client decides the data that the API should return to the client.

If you develop an application that uses RESTful architecture, the number of endpoints may grow over time, making maintenance a nightmare. If you’re using GraphQL, you might be able to get all the data you need using just one endpoint: API/Graphql.

Why do you need GraphQL?

Fewer roundtrips to the server – GraphQL requires fewer roundtrips, i.e., fewer back-and-forth calls to the server to get all the data you need.

No over-fetching or under-fetching – Unlike REST, you will never have too little or too much data when using GraphQL since you can specify all the information you need from the API upfront.

No versioning problems – GraphQL does not need versioning, and if you do not remove fields from the types, the API clients or consumers will not break.

Reduced bandwidth – GraphQL usually requires fewer requests and less bandwidth. You can get all the data you need using a single API call to the API endpoint. Since you can specify the data you need, rather than retrieving all fields for a type, you may retrieve only the ones you need, thus reducing bandwidth and resource usage.

Documentation – GraphQL is adept at creating GraphQL endpoints documentation, much like Swagger does for REST endpoints.

Despite all the advantages GraphQL has to offer, there are a few downsides as well. GraphQL is complex, and it is difficult to implement caching or rate-limiting in GraphQL than in REST.

How does a GraphQL query work?

Each GraphQL query passes through three phases: parse, validate and execute. In the parse phase, the GraphQL query is tokenized and parsed into a representation known as an abstract syntax tree. In the validation phase, the graphical query is validated against the schema as shown in Figure 1.

Image showing the GraphQL execution engine

Figure 1: GraphQL execution

Finally, in the execute phase, the GraphQL runtime walks through the abstract syntax tree from the tree’s root, retrieves and aggregates the results, and sends the data back to the GraphQL client as JSON.

GraphQL vs. REST

Take a quick look at the differences between GraphQL and REST:

  • Unlike REST, which may need multiple API calls to obtain the data you want, GraphQL exposes just one endpoint you can use to get the information you need.
  • REST only works with HTTP, while GraphQL does not need HTTP.
  • Unlike REST, which allows you to use any HTTP verb, GraphQL enables you to use only the HTTP POST verb.
  • In REST, the API specifies the request and response. On the contrary, in GraphQL, the API defines the resources accessible, and the clients or consumers can request exactly the data they need from the API.
  • When working with REST, the server determines the size of the resource. On the contrary, with GraphQL, the API specifies the accessible resources, and the client requests just what it needs.
  • REST and GraphQL are both platform and language-neutral, and both can return JSON data.

Goals of GraphQL: What Problem Does It Solve?

There are several downsides of REST:

  • Over-fetching – this implies your REST API sends you more data than you need
  • Under-fetching – this implies your REST API sends you less data than you need
  • Multiple requests – requiring multiple requests to get the data you need
  • Multiple round trips – multiple requests required to complete an execution before you can proceed

Over-fetching and under-fetching are two of the common problems you would often encounter when working with REST APIs. This is explained in more detail in the next section.

The Problem of Under-Fetching and Over-Fetching Explained

Here is a typical example of REST endpoints for a typical application that manages blog posts.

To aggregate the data, you will have to make several calls to the endpoints shown here. Note that a request to the /blogposts endpoint would fetch the list of blogposts together with authorId, but it will not return author data. You need to make a call to /authors/{authorId} multiple times to get author details of the authors. This problem is known as under-fetching since your API payload contains less data than you need. You can take advantage of Backend for Frontend or the Gateway Aggregation pattern to solve this problem. Still, in either case, you will need multiple calls to the API endpoints.

On the contrary, your API payload might be too verbose as well. For example, you might want to know only details of the blogposts by calling the /blogposts endpoint, but your payload will also contain authorId. This problem is known as over-fetching, which implies that your API payload comprises more data than you need, hence consuming more network bandwidth. Here’s where GraphQL comes to the rescue.

Building Blocks of GraphQL

The main building blocks of GraphQL comprise schemas and types.

Schema

In GraphQL, there is just one endpoint. This endpoint provides a schema used to inform API consumers about the functionality available for clients to consume, i.e., what data they may expect and what actions they can perform. A Schema in GraphQL is a class that extends the Schema class of the GraphQL.Types namespace.

GraphQL has three primary operations: Query for reading data, Mutation for writing data, and Subscription for receiving real-time updates. A schema contains Query, Mutation, and a Subscription..

  • Query – In GraphQL, you can take advantage of queries for fetching or consuming data efficiently. The consumer or the client can mention the field or fields it needs instead of getting data for all the fields from a particular type. The client can only consume the fields that the API has exposed.
  • Mutation – In GraphQL, mutations are used to add, modify, or delete data. The client can only take advantage of the mutations that the schema has exposed to modify the data. In other words, a GraphQL client cannot manipulate data exposed by the API unless there is an appropriate mutation available.
  • Subscriptions – In GraphQL, subscriptions allow a server to send data to its clients, notifying them when events occur. Subscriptions support event-driven architectures, and they use WebSockets to provide real-time notifications.

GraphQL Object Types

One of the essential components of GraphQL schema is the object type, used to describe the kind of item that may be retrieved through your API. Object Types in GraphQL are represented using GraphQL.Types.ObjectGraphType class and contain fields and methods.

Implementing a GraphQL API in ASP.NET Core

Now leverage all learned thus far to build an application that uses GraphQL for performing CRUD operations.

Getting Started: The Solution Structure

Figure 2 below illustrates the solution structure of the completed application.

Image showing the completed application

Figure 2: Application structure

As you can see, there is only one project in the Solution for the sake of simplicity. The DataAccess and GraphQL solution folders are under the root of the project. The Models solution folder is under the DataAccess solution folder. So, when this project is compiled, the following three libraries will be generated:

  • BlogPostsmanagementSystem.dll
  • BlogPostsManagementSystem.DataAccess.dll
  • BlogPostsManagementSystem.DataAccess.Models.dll

To help understand the organization of your code, including the dependencies, you can take advantage of CodeMaps in Visual Studio. Figure 3 below shows the CodeMap for this solution generated in Visual Studio 2019.

Image showing the codemaps

Figure 3: Organization of Code and Dependencies as Viewed using CodeMaps

Steps to build a GraphQL API in ASP.NET Core 5

To build the application discussed in this article, follow these steps:

  1. Create a new ASP.NET Core 5 application
  2. Install the NuGet Packages
  3. Create the Models
  4. Create the Data Context
  5. Register the Data Context
  6. Create the Repositories
  7. Add Services to the Container
  8. Build the GraphQL Schema
  9. Query
  10. Mutation
  11. Subscription
  12. Create the Resolvers
  13. Configure the GraphQL Middleware

Create a new ASP.NET Core 5 Application

First off, create a new ASP.NET Core 5 project. To do this, execute the following command at the shell:

When you execute the above command, a new ASP.NET Core 5 project without HTTPS support will be created in the current directory.

You can now take advantage of Visual Studio 2019 to open the project and make changes as needed. You’ll use this project in the sections that follow.

Install the NuGet Packages

In this example, you’ll take advantage of HotChocolate for working with GraphQL. Hot Chocolate is an open-source .NET GraphQL platform that adheres to the most current GraphQL specifications. It serves as a wrapper around the GraphQL library, making building a full-fledged GraphQL server easier.

HotChocolate is very simple to set up and configure and removes the clutter from creating GraphQL schemas. You can take advantage of HotChocolate to create a GraphQL layer on top of your existing application layer.

Since support for GraphQL is not in-built in ASP.NET Core, you’ll need to install the necessary NuGet packages via the NuGet Package Manager or the NuGet Package Manager Console.

You’ll need to install the following packages:

To do this, run the following commands at the NuGet Package Manager Console Window:

Alternatively, you can install these packages by executing the following commands at the shell:

Run the application now, then add /playground to the URL to view the playground. . Here’s how the output will look in the web browser.

A screenshot of a running the application

Figure 4: Output from web browser

Create the Models

Create a solution folder called DataAccess at the root of the project. Create another solution folder inside the DataAccess folder called Models; this is where the entity classes will go.

To make things simple, you’ll use two model classes in this example named Author and BlogPost. Select your project in the Solution Explorer Window, right-click and select Add -> New Folder. Inside this folder, create two .cs files named Author.cs and BlogPost.cs with the following content:

Author.cs

BlogPost.cs

The BlogPost class contains a reference to the Author class. Hence a BlogPost can be written by only one author, but an author can write many blog posts.

Build the DataContext

This example takes advantage of Entity Framework Core (in-memory) to work with data. Create a class called ApplicationDbContext inside the DataAccess solution folder of your project and write the following code in it:

ApplicationDbContext.cs

Register a Data Context Factory

Now that the data context is ready, you should register it. However, you’ll register a DbContextFactory in lieu of registering a DbContext instance since it would allow for easy creation of DbContext instances in the application when needed.

You might often want to perform multiple units-of-work within a single HTTP request. In such cases, you can use the AddDbContextFactory method to register a factory (in the ConfigureServices method of the Startup class) for creating DbContext instances. Then you can leverage constructor injection to access the factory in your application.

The following code snippet illustrates how you can take advantage of the AddDbContextFactory method to register a DbContextFactory instance:

The above code informs Entity Framework Core to create an in-memory database named BlogsManagement.

Create the Repositories

Create an interface named IAuthorRepository in a file called IAuthorRepository.cs inside the DataAccess solution folder of your project with the following code in there. Make sure the interfaces are public.

IAuthorRepository.cs

Create another interface named IBlogPostRepository in the same folder with the following code:

IBlogRepository.cs

The AuthorRepository and BlogPostRepository classes will implement the interfaces IAuthorRepository and IBlogPostRepository, respectively.

Create a file named AuthorRepository.cs in the DataAccess solution folder with the following code:

AuthorRepository.cs

Inside the same solution folder, create a file named BlogPostRepository.cs. Replace the default generated code using the following code:

BlogPostRepository.cs

Add Services to the Container

You should now add the following services in the ConfigureServices method of the Startup class so that you can take advantage of dependency injection to access instances of these types.

Build the GraphQL Schema

A GraphQL Schema comprises the following:

  • Query
  • Mutations
  • Subscriptions

Since GraphQL is not bound to any language or framework, it is not adept at understanding the CLR classes, i.e., C# POCO classes. In GraphQL, types are used to specify the fields of the domain classes you would like to expose. You’ll now create two classes, namely AuthorType in a file named AuthorType.cs and another class named BlogPostType in a file called BlogPostType.cs.

To create a type in GraphQL, you should create a class that extends ObjectGraphType<T> and pass your entity type as an argument. You should also register the properties of the class as Field types so that GraphQL can recognize this type.

Create your GraphQL folder, then create the following two classes in the files AuthorType.cs and BlogPostType.cs , respectively inside the folder.

AuthorType.cs

BlogPostType.cs

Query

You also need a class that would fetch author and blog post-related data. To do this, create a file called AuthorQuery.cs with the following content inside.

Query.cs

Mutation

GraphQL uses mutation to allow the clients or consumers of an API to add, remove or modify data on the servers. You will need a query type to read data – this was discussed earlier.

Create a class called Mutation in a file named Mutation.cs inside the GraphQL solution folder and add the following code:

Mutation.cs

Subscription

You can take advantage of subscriptions in GraphQL to integrate real-time functionality in your GraphQL applications. Subscriptions enable servers to send data to subscribed clients to notify them when an event occurs. Subscriptions use WebSockets to allow clients to subscribe to notifications emails in real-time. The server executes the query again and then sends the updated results to the subscribed event.

Now, create a class named Subscription in a file called Subscription.cs and replace the default code with the following:

Subscription.cs

Create the Resolvers

A resolver is a function responsible for populating data for one field of your schema. In other words, it is a function that resolves the value of a type of field within a schema. Resolvers can return objects and scalars such as Strings, Numbers, or Booleans. You can define how it populates the data, including fetching data from a third-party API or back-end database.

Create a class called AuthorResolver in a file named AuthorResolver.cs inside the GraphQL solution folder with the following code:

AuthorResolver.cs

Create another class named BlogPostResolver in a file called BlogPostResolver.cs with the following code:

BlogPostResolver.cs

Configuring the GraphQL Middleware

Write the following code in the ConfigureServices method of the Startup class to add GraphQLServer to the container:

A GraphQL server can expose data via GraphQL API endpoints so that the same data can be consumed by the clients (mobile clients, web clients, etc.) or the consumers of the API.

Next, write the following code in the Configure method of the Startup class to configure the GraphQL endpoint:

At this moment, your ConfigureServices method should look like this:

You should include the following namespaces in the Startup.cs file:

Here’s the complete source code of the Startup class for your reference:

Startup.cs

GraphQL in Action!

Now it’s time to execute GraphQL queries using HotChocolate. Run the application, remembering to have /playground in the URL.

Query

Here’s an example of a GraphQL query you can use to get the data about all authors.

When you execute this query, here’s how the output would look like:

Image showing the query output

Figure 5: Query output

If you would like to get the data about a particular author together with the blogs they have written, you can take advantage of the following query instead.

Run the above query. Figure 6 below shows the output in the Playground tool.

Image showing output of playground tool

Figure 6: Output in Playground tool

Mutation

Now write the following query to test mutation:

When you run it, you’ll observe that the CreateAuthor method of your Mutation class is called. Note that the breakpoint is hit successfully.

Image showing the CreateAuthor method

Figure 7: CreateAuthor method

Subscription

To test Subscription, execute the application, browse to the /playground endpoint, and write the query shown below:

When you click the Execute button, the application subscribes to the OnAuthorGet event.

Image showing execute

Figure 8: Click Execute button

Next, launch the same URL in another browser window and write and execute the query shown in Figure 9.

Image showing Launch and execute the query

Figure 9: Launch and execute the query

This query will trigger the OnAuthorsGet event as shown in Figure 10.

Image showing OnAuthors event

Figure 10: The OnAuthorsGet event

Summary

GraphQL is an open-source API standard developed by Facebook that provides a powerful, flexible, and versatile alternative to REST. GraphQL supports declarative data fetching, which allows the user to specify precisely the data it needs. HotChocolate, an implementation of GraphQL, can be used to create GraphQL servers in ASP.NET Core.

If you liked this article, you might also like Building and consuming GraphQL API in ASP.NET Core 3.1 – Simple Talk (red-gate.com).