Introduction
GraphQL.org is the best place to get started learning GraphQL. Here is an excerpt from the introduction:
GraphQL is a query language for your API, and a server-side runtime for executing queries by using a type system you define for your data. GraphQL isn't tied to any specific database or storage engine and is instead backed by your existing code and data.
A GraphQL service is created by defining types and fields on those types, then providing functions for each field on each type.
Here is a "Hello World" example for GraphQL.NET using the System.Text.Json serialization engine.
using System;
using System.Threading.Tasks;
using GraphQL;
using GraphQL.Types;
using GraphQL.SystemTextJson;
public class Program
{
public static async Task Main(string[] args)
{
var schema = Schema.For(@"
type Query {
hello: String
}
");
var json = await schema.ExecuteAsync(_ =>
{
_.Query = "{ hello }";
_.Root = new { Hello = "Hello World!" };
});
Console.WriteLine(json);
}
}
Output
{
"data": {
"hello": "Hello World!"
}
}
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. The basics of
both are demonstrated using the following schema definition.
!
signifies a field is non-nullable.
type Droid {
id: String!
name: String!
}
type Query {
hero: Droid
}
Schema First Approach
The Schema first approach relies upon the GraphQL schema language, coding conventions, and tries to provide a minimal amount of syntax. It is the easiest to get started though it does not currently support some advanced scenarios.
Use the optional
GraphQLMetadata
attribute to customize the mapping to the schema type.
public class Droid
{
public string Id { get; set; }
public string Name { get; set; }
}
public class Query
{
[GraphQLMetadata("hero")]
public Droid GetHero()
{
return new Droid { Id = "1", Name = "R2-D2" };
}
}
var schema = Schema.For(@"
type Droid {
id: String!
name: String!
}
type Query {
hero: Droid
}
", _ => {
_.Types.Include<Query>();
});
var json = await schema.ExecuteAsync(_ =>
{
_.Query = "{ hero { id name } }";
});
Output
{
"data": {
"hero": {
"id": "1",
"name": "R2-D2"
}
}
}
GraphType First Approach
The GraphType
first approach can be more verbose, but gives you access to all of the
provided properties of your GraphType
's and Schema
. You are required to use
inheritance to leverage that functionality.
using System;
using System.Threading.Tasks;
using GraphQL;
using GraphQL.Types;
using GraphQL.SystemTextJson;
public class Droid
{
public string Id { get; set; }
public string Name { get; set; }
}
public class DroidType : ObjectGraphType<Droid>
{
public DroidType()
{
Field(x => x.Id).Description("The Id of the Droid.");
Field(x => x.Name).Description("The name of the Droid.");
}
}
public class StarWarsQuery : ObjectGraphType
{
public StarWarsQuery()
{
Field<DroidType>("hero")
.Resolve(context => new Droid { Id = "1", Name = "R2-D2" });
}
}
public class Program
{
public static async Task Main(string[] args)
{
var schema = new Schema { Query = new StarWarsQuery() };
var json = await schema.ExecuteAsync(_ =>
{
_.Query = "{ hero { id name } }";
});
Console.WriteLine(json);
}
}
Output
{
"data": {
"hero": {
"id": "1",
"name": "R2-D2"
}
}
}
Schema First Nested Types
You can provide multiple "top level" schema types using the Schema first approach.
public class Droid
{
public string Id { get; set; }
public string Name { get; set; }
}
public class Character
{
public string Name { get; set; }
}
public class Query
{
[GraphQLMetadata("hero")]
public Droid GetHero()
{
return new Droid { Id = "1", Name = "R2-D2" };
}
}
[GraphQLMetadata("Droid", IsTypeOf=typeof(Droid))]
public class DroidType
{
public string Id([FromSource] Droid droid) => droid.Id;
public string Name([FromSource] Droid droid) => droid.Name;
// these two parameters are optional
// IResolveFieldContext provides contextual information about the field
public Character Friend(IResolveFieldContext context, [FromSource] Droid source)
{
return new Character { Name = "C3-PO" };
}
}
public class Program
{
public static async Task Main(string[] args)
{
var schema = Schema.For(@"
type Droid {
id: String!
name: String!
friend: Character
}
type Character {
name: String!
}
type Query {
hero: Droid
}
", _ =>
{
_.Types.Include<DroidType>();
_.Types.Include<Query>();
});
var json = await schema.ExecuteAsync(_ =>
{
_.Query = "{ hero { id name friend { name } } }";
});
Console.WriteLine(json);
}
}
Output:
{
"data": {
"hero": {
"id": "1",
"name": "R2-D2",
"friend": {
"name": "C3-PO"
}
}
}
}