Code samples used in this blog series have been updated to latest version of .NET Core (5.0.4) and GraphQL-Dotnet (4.2.0). Follow this link to get the updated samples.
Tired of REST? Let's talk about GraphQL
. GraphQL provides a declarative way in which you can fetch data from the server. You can read about every bit of goodness that is baked into GraphQL on the official site.
However, in this series of blog posts, I'm going to deal with .NET Core and will show how you can integrate GraphQL
with it and use it as a query language for your API.
Meaning that you only declare the properties you need (In contrast to restful API where you call a specific endpoint for a fixed set of data and then you dig out the properties that you are looking for)
To work with C#, the community has provided an open-source port for GraphQL called graphql-dotnet and we are going to use that. So, let's get started, shall we?
Start by creating a blank .NET Core Console App.
dotnet new console
I'm using the latest version of GraphQL dotnet and related libraries. Hence, I'm fetching the packages from this specific package source. If you are using Visual Studio for development, then add the package source from Tools -> Options -> NuGet Package Manager - > Package Sources
Now, add these two packages for starter,
If you are using dotnet CLI, add those packages with following commands,
dotnet add package GraphQL -s https://www.myget.org/F/graphql-dotnet/api/v3/index.json -v 3.0.0-preview-1621
dotnet add package GraphQL.NewtonsoftJson -s https://www.myget.org/F/graphql-dotnet/api/v3/index.json -v 3.0.0-preview-1621
dotnet restore
This series of articles will be updated with each version updates of the packages, hence using the most recent alpha releases. If I forget to update the article and the example code doesn't work, leave a comment below saying, Update Needed
.
There are two ways you can build your schema. One is with a Schema first approach using the GraphQL schema language. The other is a GraphType
or code-first approach by writing GraphType
classes.
Assuming you already know a bit about GraphQL. So, consider a simple hello world app: we will query for a 'hello' property to the server and it will return a 'world' string. So, the property hello will be a string type.
The Schema first approach relies upon the GraphQL schema language. Following shows a Schema first approach,
using System;
using System.Threading.Tasks;
using GraphQL;
using GraphQL.Types;
using GraphQL.NewtonsoftJson;
namespace Hello.GraphQL
{
class Program
{
static async Task Main(string[] args)
{
var schema = Schema.For(@"
type Query {
hello: String
}"
);
var json = await schema.ExecuteAsync(_ =>
{
_.Query = "{ hello }";
_.Root = new { hello = "world" };
});
Console.WriteLine(json);
}
}
}
The similar can be written in the code-first approach as well. Let's create a query
and call it HelloWorldQuery
. It's a simple class used to define fields of the query. Any query class should be extended from the ObjectGraphType
. So, the HelloWorldQuery
class with a string Field
should be as followings,
class HelloWorldQuery : ObjectGraphType
{
public HelloWorldQuery()
{
Field<StringGraphType>(
name: "hello",
resolve: context => "world"
);
}
}
Fields are defined in the constructor function of the query class.
Notice that we are using the generic version of the Field
and passing a GraphQL string type (StringGraphType
) to let the query know that the hello
field contains a string type result.
Now that we have a query, next we need to build a schema out of it.
In the Main
method of Program.cs
, delete the existing code and paste the following code,
class Program
{
static async Task Main(string[] args)
{
var schema = new Schema { Query = new HelloWorldQuery() };
var json = await schema.ExecuteAsync(_ =>
{
_.Query = "{ hello }";
});
Console.WriteLine(json);
}
}
Notice how we create a new GraphQL schema by assigning the Schema
property with an instance of HelloWorldQuery
object.
ExecuteAsync() is an extension method of ISchema
that takes an Action of type ExecutionOptions. There it initializes the schema and executes the provided query against it.
Carefully look at the string assigned to the Query
(_.Query). Here we are only asking for the hello
field.
Finally, the result of the execution is converted to JSON. Last but not least we print out JSON to the console.
Now, run the application,
dotnet run
You will get the following response in the console,
{
"data": {
"hello": "world"
}
}
So, as you can see it's not so difficult. We can add another field, say howdy
and make it return a string result universe
. To do that add another field in the HelloWorldQuery
class as followings,
Field<StringGraphType>(
name: "howdy",
resolve: context => "universe"
);
Now go back to the Starup.cs
, and this time only asks for the howdy { howdy }
field in the query. You will have the following response,
{
"data": {
"howdy": "universe"
}
}
And you can also ask for both fields by passing a query like the following,
{
hello
howdy
}
And you will have the following response,
{
"data": {
"hello": "world"
"howdy": "universe"
}
}
So, you get the point. You are asking for the things you are interested in a declarative manner. And GraphQL is intelligent enough to understand your needs and giving you back the appropriate response.
We only scratched the surface here. This hello world example was needed because in the next post when we will start building the middleware; we won't have any problems understanding every line of the code.
Comments