heart

Trait Filter

Source
pub trait Filter: FilterBase {
    // Provided methods
    fn and<F>(self, other: F) -> And<Self, F>
       where Self: Sized,
             <Self::Extract as Tuple>::HList: Combine<<<F as FilterBase>::Extract as Tuple>::HList>,
             F: Filter + Clone,
             <F as FilterBase>::Error: CombineRejection<Self::Error> { ... }
    fn or<F>(self, other: F) -> Or<Self, F>
       where Self: Sized + Filter<Error = Rejection>,
             F: Filter,
             <F as FilterBase>::Error: CombineRejection<Self::Error> { ... }
    fn map<F>(self, fun: F) -> Map<Self, F>
       where Self: Sized,
             F: Func<Self::Extract> + Clone { ... }
    fn then<F>(self, fun: F) -> Then<Self, F>
       where Self: Sized,
             F: Func<Self::Extract> + Clone,
             <F as Func<Self::Extract>>::Output: Future + Send { ... }
    fn and_then<F>(self, fun: F) -> AndThen<Self, F>
       where Self: Sized,
             F: Func<Self::Extract> + Clone,
             <F as Func<Self::Extract>>::Output: TryFuture + Send,
             <<F as Func<Self::Extract>>::Output as TryFuture>::Error: CombineRejection<Self::Error> { ... }
    fn or_else<F>(self, fun: F) -> OrElse<Self, F>
       where Self: Sized + Filter<Error = Rejection>,
             F: Func<Rejection>,
             <F as Func<Rejection>>::Output: TryFuture<Ok = Self::Extract> + Send,
             <<F as Func<Rejection>>::Output as TryFuture>::Error: IsReject { ... }
    fn recover<F>(self, fun: F) -> Recover<Self, F>
       where Self: Sized + Filter<Error = Rejection>,
             F: Func<Rejection>,
             <F as Func<Rejection>>::Output: TryFuture + Send,
             <<F as Func<Rejection>>::Output as TryFuture>::Error: IsReject { ... }
    fn unify<T>(self) -> Unify<Self>
       where Self: Sized + Filter<Extract = (Either<T, T>,)>,
             T: Tuple { ... }
    fn untuple_one<T>(self) -> UntupleOne<Self>
       where Self: Sized + Filter<Extract = (T,)>,
             T: Tuple { ... }
    fn with<W>(self, wrapper: W) -> <W as WrapSealed<Self>>::Wrapped
       where Self: Sized,
             W: Wrap<Self> { ... }
    fn boxed(self) -> BoxedFilter<Self::Extract>
       where Self: Sized + Send + Sync + 'static,
             Self::Extract: Send,
             Self::Error: Into<Rejection> { ... }
}
Expand description

Composable request filters.

A Filter can optionally extract some data from a request, combine it with others, mutate it, and return back some value as a reply. The power of Filters come from being able to isolate small subsets, and then chain and reuse them in various parts of your app.

§Extracting Tuples

You may notice that several of these filters extract some tuple, often times a tuple of just 1 item! Why?

If a filter extracts a (String,), that simply means that it extracts a String. If you were to map the filter, the argument type would be exactly that, just a String.

What is it? It’s just some type magic that allows for automatic combining and flattening of tuples. Without it, combining two filters together with and, where one extracted (), and another String, would mean the map would be given a single argument of ((), String,), which is just no fun.

Provided Methods§

Source

fn and<F>(self, other: F) -> And<Self, F>
where Self: Sized, <Self::Extract as Tuple>::HList: Combine<<<F as FilterBase>::Extract as Tuple>::HList>, F: Filter + Clone, <F as FilterBase>::Error: CombineRejection<Self::Error>,

Composes a new Filter that requires both this and the other to filter a request.

Additionally, this will join together the extracted values of both filters, so that map and and_then receive them as separate arguments.

If a Filter extracts nothing (so, ()), combining with any other filter will simply discard the (). If a Filter extracts one or more items, combining will mean it extracts the values of itself combined with the other.

§Example
use warp::Filter;

// Match `/hello/:name`...
warp::path("hello")
    .and(warp::path::param::<String>());
Source

fn or<F>(self, other: F) -> Or<Self, F>
where Self: Sized + Filter<Error = Rejection>, F: Filter, <F as FilterBase>::Error: CombineRejection<Self::Error>,

Composes a new Filter of either this or the other filter.

§Example
use std::net::SocketAddr;
use warp::Filter;

// Match either `/:u32` or `/:socketaddr`
warp::path::param::<u32>()
    .or(warp::path::param::<SocketAddr>());
Source

fn map<F>(self, fun: F) -> Map<Self, F>
where Self: Sized, F: Func<Self::Extract> + Clone,

Composes this Filter with a function receiving the extracted value.

§Example
use warp::Filter;

// Map `/:id`
warp::path::param().map(|id: u64| {
  format!("Hello #{}", id)
});
§Func

The generic Func trait is implemented for any function that receives the same arguments as this Filter extracts. In practice, this shouldn’t ever bother you, and simply makes things feel more natural.

For example, if three Filters were combined together, suppose one extracts nothing (so ()), and the other two extract two integers, a function that accepts exactly two integer arguments is allowed. Specifically, any Fn(u32, u32).

Without Product and Func, this would be a lot messier. First of all, the ()s couldn’t be discarded, and the tuples would be nested. So, instead, you’d need to pass an Fn(((), (u32, u32))). That’s just a single argument. Bleck!

Even worse, the tuples would shuffle the types around depending on the exact invocation of ands. So, unit.and(int).and(int) would result in a different extracted type from unit.and(int.and(int)), or from int.and(unit).and(int). If you changed around the order of filters, while still having them be semantically equivalent, you’d need to update all your maps as well.

Product, HList, and Func do all the heavy work so that none of this is a bother to you. What’s more, the types are enforced at compile-time, and tuple flattening is optimized away to nothing by LLVM.

Source

fn then<F>(self, fun: F) -> Then<Self, F>
where Self: Sized, F: Func<Self::Extract> + Clone, <F as Func<Self::Extract>>::Output: Future + Send,

Composes this Filter with an async function receiving the extracted value.

The function should return some Future type.

§Example
use warp::Filter;

// Map `/:id`
warp::path::param().then(|id: u64| async move {
  format!("Hello #{}", id)
});
Source

fn and_then<F>(self, fun: F) -> AndThen<Self, F>
where Self: Sized, F: Func<Self::Extract> + Clone, <F as Func<Self::Extract>>::Output: TryFuture + Send, <<F as Func<Self::Extract>>::Output as TryFuture>::Error: CombineRejection<Self::Error>,

Composes this Filter with a fallible async function receiving the extracted value.

The function should return some TryFuture type.

The Error type of the return Future needs be a Rejection, which means most futures will need to have their error mapped into one.

Rejections are meant to say “this filter didn’t accept the request, maybe another can”. So for application-level errors, consider using Filter::then instead.

§Example
use warp::Filter;

// Validate after `/:id`
warp::path::param().and_then(|id: u64| async move {
    if id != 0 {
        Ok(format!("Hello #{}", id))
    } else {
        Err(warp::reject::not_found())
    }
});
Source

fn or_else<F>(self, fun: F) -> OrElse<Self, F>
where Self: Sized + Filter<Error = Rejection>, F: Func<Rejection>, <F as Func<Rejection>>::Output: TryFuture<Ok = Self::Extract> + Send, <<F as Func<Rejection>>::Output as TryFuture>::Error: IsReject,

Compose this Filter with a function receiving an error.

The function should return some TryFuture type yielding the same item and error types.

Source

fn recover<F>(self, fun: F) -> Recover<Self, F>
where Self: Sized + Filter<Error = Rejection>, F: Func<Rejection>, <F as Func<Rejection>>::Output: TryFuture + Send, <<F as Func<Rejection>>::Output as TryFuture>::Error: IsReject,

Compose this Filter with a function receiving an error and returning a new type, instead of the same type.

This is useful for “customizing” rejections into new response types. See also the rejections example.

Source

fn unify<T>(self) -> Unify<Self>
where Self: Sized + Filter<Extract = (Either<T, T>,)>, T: Tuple,

Unifies the extracted value of Filters composed with or.

When a Filter extracts some Either<T, T>, where both sides are the same type, this combinator can be used to grab the inner value, regardless of which side of Either it was. This is useful for values that could be extracted from multiple parts of a request, and the exact place isn’t important.

§Example
use std::net::SocketAddr;
use warp::Filter;

let client_ip = warp::header("x-real-ip")
    .or(warp::header("x-forwarded-for"))
    .unify()
    .map(|ip: SocketAddr| {
        // Get the IP from either header,
        // and unify into the inner type.
    });
Source

fn untuple_one<T>(self) -> UntupleOne<Self>
where Self: Sized + Filter<Extract = (T,)>, T: Tuple,

Convenience method to remove one layer of tupling.

This is useful for when things like map don’t return a new value, but just (), since warp will wrap it up into a ((),).

§Example
use warp::Filter;

let route = warp::path::param()
    .map(|num: u64| {
        println!("just logging: {}", num);
        // returning "nothing"
    })
    .untuple_one()
    .map(|| {
        println!("the ((),) was removed");
        warp::reply()
    });
use warp::Filter;

let route = warp::any()
    .map(|| {
        // wanting to return a tuple
        (true, 33)
    })
    .untuple_one()
    .map(|is_enabled: bool, count: i32| {
        println!("untupled: ({}, {})", is_enabled, count);
    });
Source

fn with<W>(self, wrapper: W) -> <W as WrapSealed<Self>>::Wrapped
where Self: Sized, W: Wrap<Self>,

Wraps the current filter with some wrapper.

The wrapper may do some preparation work before starting this filter, and may do post-processing after the filter completes.

§Example
use warp::Filter;

let route = warp::any()
    .map(warp::reply);

// Wrap the route with a log wrapper.
let route = route.with(warp::log("example"));
Source

fn boxed(self) -> BoxedFilter<Self::Extract>
where Self: Sized + Send + Sync + 'static, Self::Extract: Send, Self::Error: Into<Rejection>,

Boxes this filter into a trait object, making it easier to name the type.

§Example
use warp::Filter;

fn impl_reply() -> warp::filters::BoxedFilter<(impl warp::Reply,)> {
    warp::any()
        .map(warp::reply)
        .boxed()
}

fn named_i32() -> warp::filters::BoxedFilter<(i32,)> {
    warp::path::param::<i32>()
        .boxed()
}

fn named_and() -> warp::filters::BoxedFilter<(i32, String)> {
    warp::path::param::<i32>()
        .and(warp::header::<String>("host"))
        .boxed()
}

Implementors§

Source§

impl<T> Filter for T
where T: FilterBase,