seanmonstar / warp

A super-easy, composable, web server framework for warp speeds.
https://seanmonstar.com/post/176530511587/warp
MIT License
9.53k stars 715 forks source link

Make `Option<F>` a filter when F is a filter #1060

Open futursolo opened 1 year ago

futursolo commented 1 year ago

Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

I wish to make a route / filter that is enabled based on command line argument. However, I find it is kind of cumbersome to have a filter optionally enabled.

I can currently find 3 solutions:

  1. boxing filter and assigning to variable
let mut f = base_filter().boxed();

// invoked with --with-extra-feature
if args.with_extra_feature {
    f = f.or(extra_filter()).unify().boxed();
}

f = f.or(other_filters());

However, this requires coercing filter to the same exact type, which means calling .unify().boxed() after every or() call and all filters needs to call into_response() manually to convert to a Response.

  1. use reject() when this filter is not needed.
base_filter()
    .or(
        if args.with_extra_feature {
            extra_filter().boxed()
        } else {
            reject_as_response().boxed()
        }
    )

However, this still requires me to make a custom reject filter that returns a Extract = Response.

  1. check with_extra_feature at each request

I would like to avoid this option as it is only determined by a factor that does not change after the program starts.

Describe the solution you'd like A clear and concise description of what you want to happen.

If we make Option<F> where F: Filter implement Filter, where None always reject.

Then the above can be simplified to:

let f = base_filter()
    .or(args.with_extra_feature.then(extra_filter))
    .or(other_filters());

Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.

  1. or_maybe

Implements a method like or, but accepts an Option<F> where None ignores the filter (rejects?).

let f = base_filter()
    .or_maybe(args.with_extra_feature.then(extra_filter))
    .or(other_filters());
  1. Either<L, R>

Similar to futures::future::Either, but accepts 2 filters instead.

let f = base_filter();

let f = if args.with_extra_feature { f.or(extra_filter()).left() } else { f.right() };

Additional context Add any other context or screenshots about the feature request here.

N/A