GraphQL is this technology created by Facebook that enables the frontend to negotiate with the backend for what data it wants. It also enables the builder of the API to stitch together data from different APIs, should you wish it. It's a very cool piece of technology and it's not just for JavaScript, you can definitely use it for your next project in .Net.
In this article we will cover:
- WHY, why do we want this technology to build APIs from
- WHAT, what are the parts it consists of
- Demo, let's build an API and learn how we get that to work with our data sources
Resources
GraphQL.org
This is the website for the GraphQL organization. It contains a lot of information on why GraphQL was built, what types exist and so on.NuGet package graphql-dotnet
This is the most popular NuGet package there is. It contains a README page that helps you get started but also demos for different types of applications like MVC for example.Starting with .Net Core in VS Code
This shows how you can get started with .Net Core in VS Code.Starter articles I wrote on .Net Core and VS Code
I wrote a collection of articles for you that is curious about .Net Core. It shows how to build different types of projects, run tests and more. It even covers how to build a Serverless API.How to build and consume GraphQL APIs in JavaScript
If you want to have a look at how things are done in JavaScript have a look at these articles I wrote.
WHY, why do we need it in the first place. What's wrong with a REST API?
GraphQL allows for content negotiation which means you will only have one endpoint. It also allows you to query for exactly the fields you want. On the backend, you can grab the data from different data sources so there definitely is a good reason to be excited, for frontend developers as well as backend developers.
WHAT, what parts does GraphQL exist of
GraphQL consists of a schema definition. You can define that schema in something called GQL, GraphQL Query Language but you can also decorate classes to respond to certain resource requests (more on that one in future articles).
Besides from the schema, there is a central concept called resolvers. A resolver is simply a function that knows what to do with an incoming query. A resolver is mapped to a certain resource.
Then you have a visual environment called GraphiQL that allows you to run queries. Some form of visual environment comes with most implementations of GraphQL.
How to query
GraphQL looks a bit special when you query it but it's quite simple. To query a resource you would type so:
{
resource
}
That's not enough, however. You also need to specify what columns you want, like so:
{
resource {
column,
column2
}
}
To query with a parameter you would instead type like so:
{
users(id:1) {
name,
created
}
}
The end result is always a JSON response that matches your query. So if we take the above query we would get something back looking like the following:
{
"data": {
"users": [{
"name" : "chris",
"created": "2018-01-01"
}]
}
}
Demo - let's build an API.
We need to mix some GraphQL theory with code. So we will introduce a concept and then show code for it.
Set up
We will need to do the following
- Create a solution
- Create a console app
- Install the GraphQL NuGet package
Create a solution
Let's start by creating a solution directory like so:
mkdir demo
cd demo
Next, let's create the actual solution file:
dotnet new sln
Create the Console app
Creating a console project is as simple as typing:
dotnet new console -o App
Then navigate into it the project directory:
cd App
Adding our GraphQL NuGet library
Next, let's add our GraphQL NuGet package
dotnet add package GraphQL
Hello GraphQL
Now we are ready to add code
// Program.cs
using System;
using GraphQL;
using GraphQL.Types;
namespace App
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var schema = Schema.For(@"
type Query {
hello: String
}
");
var root = new { Hello = "Hello World!" };
var json = schema.Execute(_ =>
{
_.Query = "{ hello }";
_.Root = root;
});
Console.WriteLine(json);
}
}
}
There are three interesting parts in the above code:
- Declaring our schema
- Defining our resolver
- Executing our query the API
Declaring our schema
The string that we feed into Schema.For
contains something called GQL or GraphQL Query Language. It defines three things generally:
- Query, this is what we can query for
- Types, we don't have any types yet but we will later on in the article.
- Mutation, this is what we can call that semantically means that we will change something
Let's especially 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
.
Resolving our query
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 like this:
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
.
Executing the query
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 using:
Console.WriteLine(json);
Schema first
This is a different approach in which we will use classes and decorate them, the idea is that the classes will contain methods that will serve as resolvers when we make a query.
To do it this way we need to do the following:
Update our schema, we need a new custom type and we need to expose it in the
Query
Create some classes that we need to support our Type, our Query and also an in-memory database
Schema update
Our schema so far had no custom types. Let's change that by adding the type Jedi
and let's also expose it as something we can query for, like so:
Schema.For(@"
type Jedi {
name: String,
side: String
}
type Query {
hello: String,
jedis: [Jedi]
}
", _ =>
{
_.Types.Include<Query>();
});
Above we are adding Jedi
as a type by writing type Jedi
and also define its properties within {}
. Then we add jedis
to the Query
and say it's of type [Jedi]
which means it's an array of Jedi
. Lastly, we give our Schema.For()
a second argument:
_.Types.Include<Query>();
This means we are pointing out a class Query
that will handle all incoming requests. We don't have that class yet so let's create it.
Creating supporting classes
First, we need the class Query
. It now has the responsibility to handle anything inside of Query
in our schema, which means it needs to handle hello
and jedis
. Let's have a look at what Query
can look like:
public class Query
{
[GraphQLMetadata("jedis")]
public IEnumerable<Jedi> GetJedis()
{
return StarWarsDB.GetJedis();
}
[GraphQLMetadata("hello")]
public string GetHello()
{
return "Hello Query class";
}
}
Here we are defining two methods GetJedis()
and GetHello()
. Note how we use the decorator GraphQLMetadata
on each of the methods to map which property in our Query
that they will handle. We see also that we make a call to a class StarWarsDB
so we need to create that next:
public static IEnumerable<Jedi> GetJedis()
{
return new List<Jedi>() {
new Jedi(){ Name ="Luke", Side="Light"},
new Jedi(){ Name ="Yoda", Side="Light"},
new Jedi(){ Name ="Darth Vader", Side="Dark"}
};
}
Defining what to query for
Let's define the query that we will use to Query our GraphQL API:
{ jedis { name, side } }
What we are saying above is that we want to query for jedis
and we want the columns name
and side
. Compare this to a SQL expression where we would instead type:
SELECT name, side
FROM jedis;
Let's update the code with our query like so:
var json = schema.Execute(_ =>
{
_.Query = "{ jedis { name, side } }";
});
Console.WriteLine(json);
and the result is:
That seems to work fine, alright :)
Working with parameters
Now we got a lot working already but we need to be able to handle parameters, sometimes we just want one record back so we need to filter a bigger collection based on a key. To make this happen we need to:
Update our Schema to support a query with a parameter
Create a method in our Query class that is able to parse out the parameter
Verify that everything works
Updating our schema
First off, we need to update our schema so we support a query that takes a parameter, like so:
Schema.For(@"
type Jedi {
name: String,
side: String,
id: ID
}
type Query {
hello: String,
jedis: [Jedi],
jedi(id: ID): Jedi
}
", _ =>
{
_.Types.Include<Query>();
});
We are actually doing two things above. We are adding the field id
to the Jedi
type. We are also adding this row to Query
:
jedi(id: ID): Jedi
Updating our code
Our Jedi class didn't have an Id
field so we need to add that, like so:
public class Jedi
{
public int Id { get; set; }
public string Name { get; set; }
public string Side { get; set; }
}
Next, we need to add a method to our query class, like so:
[GraphQLMetadata("jedi")]
public Jedi GetJedi(int id)
{
return StarWarsDB.GetJedis().SingleOrDefault(j => j.Id == id);
}
Note above how we just need to name match id
as an input parameter. The code itself is just a SingleOrDefault
LINQ query that gives us one entry back.
Updating the query
Let's try to query for this new resource like so:
{ jedi(id: 1) { name } }
and the result:
Works !!! :)
Summary
We have covered a lot of ground. We've introduced the GQL, GraphQL Query Language. Furthermore, we've learned how to define resources in our schema, custom types and how to resolve these. There is a lot more to learn about GraphQL but this article is already long enough. I hope this was an interesting first look at it. In the next part, we will cover how to build a Serverless API and leverage GraphQL that way and deploy it to the Cloud.
Top comments (31)
Has anyone actually bothered figuring out how to make GraphQL efficient in .Net yet?
Using something like LINQ and EF, I can optimize my database queries to only request the data I need for a REST query - and I can do so with minimal bootstrapping.
In most situations, I can just re-use a repo or unit of work with a custom DataModel, and only have to write a simple LINQ query to get results.
I'm yet to see a GraphQL implementation which isn't simply massive amounts of extra code in the backend, with no clear approach for optimizing the database queries, and a tendency to offer mutators that require access to the majority of your database.
I wish GraphQL evangelists would stop focusing on how pretty the UI code is, when all they're doing is moving the mess somewhere else, and breaking lots of existing optimizations in doing so.
Example - check out the REST API below that looks just a firstname/lastname/id/booking-count up from a potentially heavy profile table. I'd genuinely love to see an efficient and scalable way to tackle this for GraphQL as our mobile guys are chomping at the bit for GraphQL, but I'm yet to see an approach that doesn't involve massive overhead for our team.
You have a lot of great points Peter. Let me come back to you with an article describing a nested implementation and some good practices and how to tackle the N+1 problem.. I'll say this though, you are right, you are moving the problem to somewhere else, from frontend to backend.. As always it's meant to be used in specific cases not to replace REST but coexist. I'll come back with an article in 2-3 weeks, currently on holiday
Yup - my approach so far has been to provide REST APIs in the .Net portion of our stack, and allow the Swift guys to implement a GraphQL aggregator if they care enough for one.
Unfortunately, our database isn't normalized nearly as much as it should be, so pulling back entire tables hurts massively, and I'm yet to find any nice Linq2Sql or similar approaches that eliminate that as an overhead when implementing GraphQL on the .Net side.
I think this is primarily due to maturity of the toolchains, as from what I've seen, the Swift guys are going through the same overhead - it's just .Net has spent decades perfecting the REST approach to the point where I can mock one up in a comment section from memory. Our Swift guys seem to go through the same overhead regardless of REST or GraphQL at the moment however.
Thanks for the post! Have you had time to write a follow-up article on this? I am particularly curious about tackling the N+1 problem myself.
Also, if you have any tips about implementing a Relay-compatible GraphQL server in .NET (C# or F#), that would be really helpful!
Are you looking for a GraphQL to LINQ translation? Aren't there some libs for that?
Hi,
Is there an effective way of using GraphQl with MongoDb?
is this for .NET or? you could be using this github.com/remorses/mongoke to expose your database as a GraphQL API or have a look here if you just want a tutorial on how to use it dev.to/alvarojsnish/graphql-mongod... . Let me know what you had in mind ? :)
Well,
I am thinking to use GraphQl with Dotnet Core, for example: if I have a collection in mongo of games - how to use GraphQl to retrieve data without doing a GetAll() in the collection?
Is there a way to setup the Mongodb repository in Dotnet core with GraphQl?
Generally, you use a query that takes a parameter on the GraphQL side
As for dealing with .NET Core and MongoDB you have a tutorial here docs.microsoft.com/en-us/aspnet/co... . I suppose I could be writing a tutorial on GraphQL, .NET Core and MongoDB if you are interested?
Also have a look here dev.to/dotnet/how-you-can-build-a-... This shows how our request is passed from API to DB layer
I tried do to a combination of GraphQL, .NET Core and MongoDB but can seem te get the MongoDb working to you still need to use a DBContext and DBsets or can you just use IMongoCollection's like in the Microsoft tutorial?
Hi thank you for the links.
I would be very much interested in reading a tutorial on how to implement a GraphQl server with .NET Core and MongoDb.
So far only managed to implement it when all data sat in memory, which is of course not an acceptable solution.
I'm looking into a GraphQL solution currently called Hot Chocolate. It has the concept of loaders. Yes some data need to sit in memory, but not all. Maybe that can offer a path forward? hotchocolate.io/docs/introduction....
Great post!
Just a small note:
Note that the original use case for GraphQL wasn't JavaScript, it was Facebook's native mobile apps :)
It evolved to JavaScript later on, once Relay (and then Apollo) were released.
Didn't know that, thanks Daniel :)
Thank you for this amazing tutorial. I am a frontend dev trying to understand and implement a backend with graphql.
Forgive me for being naive, but I wanted to know how this is different from a REST api as we are still writing predefined queries to fetch from the db.
Great post as always 🙌👏!
I've actually never had a chance to see/try GraphQL with DotNet yet.
Most DotNet shops typically only do REST APIs unfortunately! :(
How is the intellisense with the Queries themselves?
Well there is the visual GraphiQL NuGet package that will do that :)
Hi Chris,
I barely comment on dev posts but really like your writing style, very clear and concise.
Keep up the good work 🙂
Hi Dan, really appreciate your comment, thank you :)
Great article. Really enjoyed the writing style and pace. Quick typo : "Exuting our query the API"
Great post to get started on GraphQL! I couldn't figure out how to use the DataLoader to batch requests.
Is it possible to have a small example of DataLoader in your follow up post?
Hi thanks Mrinal. Let me see what I can do :)
Lovely post, would be amazing to see a follow-up GraphQL + ASP.NET Core article :)
should be coming out next week :)
Great post, look forward to seeing the next one.
This could be exceeding useful for what I’m currently working on