Dan Schnau

Installing a GraphQL Service on dan schnau dot com

As part of an upcoming project, I'll be working with GraphQL. So before starting, I decided to set up a GraphQL API on danschnau.com first.

To accomplish this, I installed the projectgraphql-dotnet and configured it against the danschnau.com blog database.

Thanks to the GraphQL.MicrosoftDI package, as part of the graphql-dotnet project, setting up an API was a matter of one change in the application's ServiceCollection and one in the Application builder.

public void ConfigureServices(IServiceCollection services)
{
           // other services configured....
            services.AddGraphQL(b =>
            {
                b.Services.Register<GraphQLHttpMiddleware<ISchema>, GraphQLHttpMiddleware<ISchema>>(GraphQL.DI.ServiceLifetime.Singleton);
                b.AddSystemTextJson()
                 .AddErrorInfoProvider(opt => opt.ExposeExceptionDetails = true) // set to false for production
                 .AddSchema<BlogSchema>()
                 .AddGraphTypes(typeof(BlogSchema).Assembly);
            });
           // other services configured....
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
            // other stuff....
            app.UseGraphQL<ISchema>();
            app.UseGraphQLPlayground();
            // other stuff....
}

Configuring the GraphQL Schema is a matter of mapping the concepts in GraphQL to the application. GraphQL queries are always rooted in a "Query" or a "Mutation" - I think of them as GET and POST in http. In my case, I did not need a Mutation in my Schema, but only a simple Query for the purpose.

using GraphQL.Instrumentation;
using GraphQL.Types;

    public class BlogSchema : Schema
    {
        public BlogSchema(IServiceProvider serviceProvider) : base(serviceProvider)
        {
            // Query = ....
            Query = (BlogQuery)serviceProvider.GetService(typeof(BlogQuery)) ??
                throw new InvalidOperationException();

            // no mutations.
            // Mutation = ....
        }
    }

The BlogQuery defines a graphQL query that can be made, and instructions for the rest of the application to execute, or resolve, the query.

using GraphQL.Types;

    public class BlogQuery : ObjectGraphType<object>
    {
        public BlogQuery()
        {
            FieldAsync<ListGraphType<BlogType>>("blogs", "get all blogs", resolve:
                async context => await blogRepo.GetBlogsAsync());
        }
    }
}

Lastly, the GraphQL package must learn about the types needed. In my case, a BlogType:

using GraphQL.Types;

    public class BlogType : ObjectGraphType<Blog>
    {
        public BlogType() 
        {
            Name = "Blog";
            Field(b => b.BlogId).Description("The id of the blog.");
            Field(b => b.Published).Description("When the blog was first published.");
            Field(b => b.LastUpdated, nullable: true).Description("When the blog was last updated. Null if never.");
            Field(b => b.Title).Description("The Title of the Blog.");
            Field(b => b.Slug).Description("The slug for the blog, used in URL generation.");
            Field(b => b.Content).Description("The Content of the blog, serialized into HTML.");
            Field(name: "URL", expression: b => $"https://danschnau.com/blog/{b.Slug}").Description("The URL for the blog.");
        }
    }
}

The result is that if you visit https://danschnau.com/ui/playground, you get a sample client which can be used to make GraphQL queries for this blog.

demo of graphql working for danschnau.com