GraphQL WS

Besides the SignalR based server Tanka also provides a graphql-ws protocol compatible websocket server. This server can be used with apollo-link-ws.

Configure required services

This will add the required services to execution pipeline.


        [Fact]
        public void Configure_WebSockets()
        {
            /* When */
            Services.AddTankaGraphQL()
                .ConfigureSchema(() => default)
                // Add websocket services with defaults
                .ConfigureWebSockets();

            /* Then */
            var provider = Services.BuildServiceProvider();
            Assert.NotNull(provider.GetService<WebSocketServer>());
            Assert.NotNull(provider.GetService<IOptions<WebSocketServerOptions>>());
        }

Add middleware to app pipeline

app.UseWebSockets();
app.UseTankaGraphQLWebSockets("/api/graphql");

Configure protocol

When connection_init message is received from client the protocol calls AcceptAsync of the options to accept the connection. By default it accepts the connection and sends connection_ack message back to the client. You can configure this behavior with your own logic.


        [Fact]
        public async Task Configure_WebSockets_with_Accept()
        {
            /* Given */
            var called = false;
            /* When */
            Services.AddTankaGraphQL()
                .ConfigureSchema(() => default)
                // Add websockets services with accept method
                .ConfigureWebSockets(async context =>
                {
                    called = true;
                    var succeeded = true; //todo: authorize

                    if (succeeded)
                    {
                        await context.Output.WriteAsync(new OperationMessage
                        {
                            Type = MessageType.GQL_CONNECTION_ACK
                        });
                    }
                    else
                    {
                        // you must decide what kind of message to send back to the client
                        // in case the connection is not accepted.
                        await context.Output.WriteAsync(new OperationMessage
                        {
                            Type = MessageType.GQL_CONNECTION_ERROR,
                            Id = context.Message.Id
                        });

                        // complete the output forcing the server to disconnect
                        context.Output.Complete();
                    }
                });

            /* Then */
            var provider = Services.BuildServiceProvider();
            Assert.NotNull(provider.GetService<WebSocketServer>());
            var options = provider.GetRequiredService<IOptions<WebSocketServerOptions>>().Value;
            await options.AcceptAsync(new MessageContext(new OperationMessage(),
                Channel.CreateUnbounded<OperationMessage>()));
            Assert.True(called);
        }