Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A means to conditionally provide a response to a request in lieu of calling the inner service #426

Open
bassmanitram opened this issue Oct 23, 2023 · 3 comments

Comments

@bassmanitram
Copy link

Feature Request

Conditionally provide a response instead of calling the inner service.

Motivation

This middleware provides a way to conditionally skip calling the inner service
if a response is already available for the request.

Probably the simplest visual for this is providing a cached response, though it
is unlikely that this middleware is suitable for a robust response cache interface
(or, more accurately, it's not the motivation for developing this so I haven't
looked into it adequately enough to provide a robust argument for it being so!).

The premise is simple - write a (non-async) function that assesses the current request
for the possibility of providing a response before invoking the inner service. Return
the "early" response if that is possible, otherwise return the request.

The differences between using this and returning an error from a pre-inner layer are.

  1. The response will still pass through any post-inner layer processing
  2. You aren't "hacking" the idea of an error when all you are trying to do is avoid
    calling the inner service when it isn't necessary.

Possible uses:

  • A pre-inner layer produces a successful response before the inner service is called
  • Caching (though see above - this could, however, be the layer that skips the inner
    call while a more robust pre-inner layer implements the actual caching)
  • Mocking
  • Debugging
  • ...

Proposal

The idea should be fairly straightforward to implement, being a merge of the capabilities of tower predicate layers
and simple pre-service layers. The slight complications of providing alternative responses from the function,
and providing different futures from the poll method can be overcome by judicious use of enums.

For simplicity, the first iteration should only allow sync functions. Maybe at a later date async functions can be
allowed (particularly after async methods in traits become generally available), which would then allow for a
more generic stack of multiple "end" services to be constructed in the vein of the chain of responsibility pattern!

Alternatives

Since the main purpose of this middleware is, effectively, to conditionally switch from pre-request processing to post-response processing - i.e. it's effectively a Request->Request mapper or a Request->Response generator - there currently exists no general way to do this in the provided filters of the crate.

@bassmanitram
Copy link
Author

PR #427

@jplatte
Copy link
Collaborator

jplatte commented Nov 8, 2023

If you are using axum, this kind of thing is easy to do with axum::middleware::from_fn.

I'm skeptical about having this middleware (as implemented in #427) in tower-http. But maybe we could have a simplified version of axum::middleware::from_fn without all of the axum-specific bits (wdyt @davidpdrsn?).

@bassmanitram
Copy link
Author

bassmanitram commented Nov 9, 2023 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants