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);
}