This is an early preview / proof of concept providing gRPC support for Hummingbird using grpc-swift. It has not been tested with production workloads yet, so it definitely not ready for use.
Hummingbird gRPC supports:
- gRPC using Protocol Buffers over HTTP/2.
- Unary, client streaming, server streaming, and bidirectional streaming calls.
- grpc-swift Server interceptors.
- Async and SwiftNIO EventLoop based routing.
- grpc-swift generated server providers.
- proto2 and proto3.
Note
From version 0.0.4 Hummingbird gRPC supports Swift 5.10+ and requires Hummingbird 2.0.0-rc.2 and grpc-swift 1.23.0+.
Hummingbird gRPC does not currently support:
- gRPC using JSON or other serialization formats.
- gRPC Web (HTTP/1.1).
- Hummingbird middleware with gRPC.
Hummingbird gRPC uses the TLS Application-Later Protocol Negotiation to decide how to handle an incoming HTTP/2 channel. If it is negoiateed as grpc-exp
the channel will be handled directly by grpc-swift, if it is negotiated as vanilla h2
(HTTP/2), http/1.1
, or as anything else it will be handled by Hummingbird.
Currently this requires forking grpc-swift to make HTTP2ToRawGRPCServerCodec
public, and copying the HTTP2ChannelInitializer
from HummingbirdHTTP2, it is hoped both of the changes can be made upstream, allowing Hummingbird gRPC to work with the sources directly.
let app = HBApplication()
// Enable support for gRPC. You will need to configure TLS as well.
app.gRPC.addUpgrade(configuration: .init(), tlsConfiguration: .makeServerConfiguration())
// Add service providers that were generated by grpc-swift's protoc plugin
app.gRPC.addServiceProvider(EchoProvider())
// Alternatively, declare your gRPC endpoints directly using SwiftNIO EventLoop-based futures
app.gRPC.onUnary("echo.Echo", "Get", requestType: Echo_EchoRequest.self) { request, context in
let response = Echo_EchoResponse.with {
$0.text = "Swift echo get: " + request.text
}
return context.eventLoop.makeSucceededFuture(response)
}
// Or using async closures
app.gRPC.onUnary("echo.Echo", "Get", requestType: Echo_EchoRequest.self) { request, context async in
Echo_EchoResponse.with {
$0.text = "Swift echo get: " + request.text
}
}
// Start the server like normal
app.start()
app.wait()