tower-rs / tower-http

HTTP specific Tower utilities.
680 stars 159 forks source link

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

Open bassmanitram opened 10 months ago

bassmanitram commented 10 months ago

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:

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 commented 10 months ago

PR #427

jplatte commented 10 months ago

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 commented 10 months ago

Thanks for the tip for other, however my motivation is plugging into AWS's Lambda framework, so Axum isn't in the picture

On Wed, Nov 8, 2023 at 11:22 AM Jonas Platte @.***> wrote:

If you are using axum, this kind of thing is easy to do with axum::middleware::from_fn https://docs.rs/axum/latest/axum/middleware/fn.from_fn.html.

I'm skeptical about having this middleware 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 https://github.com/davidpdrsn?).

— Reply to this email directly, view it on GitHub https://github.com/tower-rs/tower-http/issues/426#issuecomment-1801549026, or unsubscribe https://github.com/notifications/unsubscribe-auth/ADAKLWSYKVH2Z2Z6S3VDTYTYDNMOTAVCNFSM6AAAAAA6LZ6B6WVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQMBRGU2DSMBSGY . You are receiving this because you authored the thread.Message ID: @.***>