feat(tonic): make it easier to add tower middleware to servers #650
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Edit: Superseded by #651
This is an attempt at making tower easier to use with tonic. It only touches the server parts because I think adding tower middleware to a client is already easy.
The main limitations of the current setup I think are:
NamedService
. This is big downside because it means middleware defined in tower cannot be used since tower doesn't know anything about tonic.http::Request
andhttp::Response
to work with tonic. Thats quite surprising since tonic already has its own request and response types.What I have so far solves 1 and 2. I'm not quite sure 3 has a good solution but might be possible to write a middleware that converts things back and forth behind the scenes.
Using tower now
With this patch adding tower middleware to a tonic server looks like:
So
Server
becomes generic over a tower layer. The layer starts out asIdentity
but can be changed with theServer::layer
method. All added services will be wrapped in that layer's service.The way I get around the
NamedService
limitation is with a new middleware calledNamed
(please bikeshed the name).Named
has two generic type parameters:NamedService
and is used when implementingNamedService for Named
.NamedService
but thats fine since we get that name from the first type.So a full type for
Named
would be something likeNamed<GreeterServer<MyGreeter>, Timeout<GreeterServer<MyGreeter>>>
. Where the name comes fromGreeterServer<MyGreeter>
but the actual service used to handle requests isTimeout<GreeterServer<MyGreeter>>
.This is also nice because
Server::layer
will show up in the docs and gives us a place to mention and demo using tower to add middleware. That should hopefully increase awareness a bit.The downside to this approach is that it complicates the types quite a bit and the type errors you get when things don't align are pretty bad. But thats hard to avoid when doing anything non trivial with tower anyway 🤷