Looking at REST vs GraphQL APIs in .NET

Both REST and GraphQL are approaches to building APIs that allow systems to communicate with each other. However, both have different mechanisms and philosophies, let’s dig into the differences.

Introduction to GraphQL

First of all, what is a GraphQL API, why would we want to use it and what does a GraphQL API look like.

Unlike a REST API, GraphQL allows for content negotiation, which means you only have one endpoint. So in a REST API, you may have endpoints like GET /customers or POST /customers, in GraphQL you use JSON to describe your query to a single endpoint.

On your backend, you can then grab data from multiple sources if needed. GraphQL consists of a schema definition. You can define that schema definition using GQL or GraphQL Query Language. You can also decorate classes to respond to certain resource requests.

The central concept is something called resolver. A resolver is a function that knows what to do with an incoming query, each resolver is mapped to a certain resource.

You also have a visual environment called GraphiQL, which allows you to run queries. Some form of visual environment comes with most implementations of GraphQL.

Queries are basically JSON, it’s simple to define a query, we just start with the resource name, for example users. Here is an example:

{
  users
}

However, you also need to specify what columns you would like to return as well, this is done using the following syntax.

{
  users {
    id,
    name
  }
}

If you would like to query with a parameter, then that’s also done using the following example.

{
  users(id: 1) {
    id,
    name
  }
}

The end result is always going to be a JSON response that matches the query you have provided. So for example, if we take the query above, the response would look something like this.

{
  "data": {
    "users": [{
      "id": 1,
      "name": "Martyn"
    }]
  }
}

There you have it, there is a quick and simple introduction to GraphQL. Now let’s look at the differences.

Differences between REST and GraphQL

Now we understand what GraphQL is and why we might want to use it, let’s now look at some of the differences compared to REST APIs.

  • Data fetching
  • Over and under fetching
  • Versioning
  • Relationships
  • Caching
  • Complexity and flexibility

Data fetching

In a REST API, the endpoints are defined by the server. Each endpoint represents a specific resource and a specific HTTP method corresponds to a specific action.

When you make a request to the endpoint, you get back exactly what you have requested, nothing more.

However, in GraphQL, the client allows you to construct the request of exactly what you need, nothing more. The client therefor defines the structure of the response, not the server. The client can also request additional resources if required, reducing the number of API calls made to the backend.

Over and under fetching

In a REST API, overfetching occurs when the server returns more data than the client needs. This can lead to wastage of both processing power and bandwidth. Underfetching in a REST API occurs when the client has to make multiple API requests to get the data it requires.

GraphQL eliminates overfetching and underfetching. The client specifies exactly what data it wants in the query, reducing the amount of data transferred over the network.

Versioning

In REST APIs, versioning is often done through the URL (e.g., /v1/users). When a new version of the API is released, a new URL is created.

GraphQL does not require versioning. It allows clients to request only the fields they need, so changes to the server’s schema do not necessarily break existing clients.

Relationships

In a REST API, relationships between resources are typically represented by URLs. For example, to get related data, you might make a separate request to a related endpoint.

GraphQL allows you to request nested or related data in a single query. This makes it more efficient when dealing with complex relationships.

Caching

RESTful APIs often rely on HTTP caching mechanisms. The server specifies caching headers (e.g., ETag, Last-Modified) to control caching behaviour.

Caching in GraphQL can be more challenging because the client defines the shape of the query. However, there are libraries and techniques available to implement caching in GraphQL.

Of course, in both scenarios you could add a service like Redis to enable more granular or complex caching scenarios.

Complexity and flexibility

REST APIs are more straightforward and easy to understand. They are well-suited for simpler applications or cases where you have a clear understanding of your data requirements.

GraphQL provides more flexibility, which can be powerful for complex applications with evolving data needs. However, it can also be more challenging to learn and implement correctly.

Creating a simple console app

First of all, let’s create a simple console application and add in the dependencies required. You can use the .NET CLI to create the project using dotnet new console -o GraphQL.

Next, we need to add the GraphQL package to our console application, again either use the .NET CLI or use the Package Manager. Both commands are below.

dotnet add package GraphQL
Install-Package -Name GraphQL

We are ready to add some code, but first, let’s look at the structure of what we will write.

  1. Declaring the schema
  2. Defining the resolver
  3. Executing the query

The string that we feed into Schema.For contains something called GQL or GraphQL Query Language. It defines three things generally:

  1. Query, this is what we can query for
  2. Types, we don’t have any types yet but we will later on in the article.
  3. Mutation, this is what we can call that semantically means that we will change something

Let us focus on the parts where we set up our schema:

var schema = Schema.For(@"
  type Query {
      hello: String
  }
");

For now, we only have the type Query and what it says is that we can query for hello and that the response is of type string, hello: string.

A schema is just one part of the puzzle. The other part is the resolver code. This piece of code is what actually handles an incoming request. In our case the resolver code looks as follows.

var root = new { Hello = "Hello World!" };

As we can see above it maps something inside of our query hello and says that, if the user asks for hello, then we will answer with Hello World.

In the below code we execute our query { hello } by assigning it to the property _.Query in the lambda expression we provide to schema.Execute().

var json = schema.Execute(_ =>
{
    _.Query = "{ hello }";
    _.Root = root;
});

Then the result of our query is assigned to our variable json and we can easily print that to the terminal.

Console.WriteLine(json);

In future posts, we will look at the schema first approach which uses classes and decorators, and how to work with parameters.

Summary

In summary, the choice between REST and GraphQL depends on your specific use case. REST is a well-established standard that works well for many applications. GraphQL, on the other hand, offers greater flexibility and efficiency in data fetching, making it a good choice for applications with complex data requirements or where optimizing network requests is critical.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.