Server

Tanka provides server components in Tanka.GraphQL.server NuGet package. It can be used to get up and running or if more control is required then you can implement your own server.

See also

Tanka Server provides two server components which can be used together or separately.

  • SignalR - server built on top of SignalR Core
  • GraphQL-WS - custom WebSockets server supporting graphql-ws messages

Following steps are required to get the server running with your schema.

  1. Build schema
  2. Configure schema options
  3. Configure server
  4. HTTP API

1. Build schema

First step for either server is to configure your schema options for execution. Schema should be built only once and cached as singleton.


        private async Task<ISchema> Create()
        {
            // Do some async work to build the schema. For example
            // load SDL from file
            await Task.Delay(0);

            // Build simple schema from SDL string
            var builder = new SchemaBuilder()
                .Sdl(
                    @"
                    type Query {
                        firstName: String!
                        lastName: String!
                    }

                    schema {
                        query: Query
                    }
                    ");

            // Bind resolvers and build
            return SchemaTools
                .MakeExecutableSchemaWithIntrospection(
                    builder,
                    new ObjectTypeMap
                    {
                        ["Query"] = new FieldResolversMap
                        {
                            {"firstName", context => ResolveSync.As("Tanka")},
                            {"lastName", UseService()}
                        }
                    });
        }

2. Configure

Next needed step is to configure server options. These options tell the executor where to get the schema and also allows configuring the validation rules for the execution. By default all validation rules from the GraphQL specification are included.


        private static void AddTanka(IServiceCollection services)
        {
            // Configure schema options
            services.AddTankaGraphQL()
                .ConfigureSchema<SchemaCache>(async cache => await cache.GetOrAdd());
        }

3. Configure server

Server components require calling their Add* methods to add required services and configure their options. Depending on the server also middleware needs to be configured using the paired Use* methods.

Configure SignalR server


        private static void AddSignalRServer(IServiceCollection services)
        {
            // Configure Tanka server
            services.AddSignalR()
                .AddTankaGraphQL();
        }

Use SignalR server


        private static void UseSignalRServer(IApplicationBuilder app)
        {
            // add SignalR
            app.UseEndpoints(routes => { routes.MapTankaGraphQLSignalR("/graphql/hub"); });
        }

Configure GraphQL WS server


        private void AddWebSocketsServer(IServiceCollection services)
        {
            // Configure websockets
            services.AddWebSockets(options => { options.AllowedOrigins.Add("https://localhost:5000"); });

            // Add Tanka GraphQL-WS server
            services.AddTankaGraphQL()
                .ConfigureWebSockets();
        }

Use GraphQL WS Server


        private void UseWebSocketsServer(IApplicationBuilder app)
        {
            // Add Websockets middleware
            app.UseWebSockets();

            // Add Tanka GraphQL-WS middleware
            app.UseEndpoints(endpoints => endpoints.MapTankaGraphQLWebSockets("/graphql/ws"));
        }

4. HTTP API

Tanka Server does not provide out of the box "server" for basic HTTP/JSON API as that can be easily implemented.

Here's an example of ASP.NET Core MVC Controller taken from the Tanka.GraphQL.Samples.Chat.Web project included in the solution.

IQueryStreamService is registered by the AddTankaGraphQL and is also used by the SignalR and GraphQL-WS based servers to execute the queries.

[]

    [Route("api/graphql")]
    public class QueryController : Controller
    {
        private readonly IQueryStreamService _queryStreamService;

        public QueryController(IQueryStreamService queryStreamService)
        {
            _queryStreamService = queryStreamService;
        }

        [HttpPost]
        public async Task<IActionResult> Post([FromBody] OperationRequest request)
        {
            var stream = await _queryStreamService.QueryAsync(new Query
            {
                Document = ParseDocument(request.Query),
                Variables = request.Variables,
                OperationName = request.OperationName
            }, Request.HttpContext.RequestAborted);

            var result = await stream.Reader.ReadAsync();

            return Ok(result);
        }
    }