Nick
Nick

Reputation: 6362

returning a warp filter from function

I'm using warp to create a server in Rust. And let's say I have these two routes setup.

let route_one = warp::get().and(warp::path("path1")).map(|| warp::reply());
let route_two = warp::get().and(warp::path("path2")).map(|| warp::reply());

warp::serve(route_one.or(route_two))
    .run(([127, 0, 0, 1], 3000))
    .await;

I would like to move the routes into their own function. What would the return type be?

For instance:

async fn get_route_one() {
     warp::get().and(warp::path("path1")).map(|| warp::reply())
}

async fn get_route_two() {
     warp::get().and(warp::path("path1")).map(|| warp::reply())
}

#[tokio::main]
async fn main() {
    warp::serve(get_route_one().or(get_route_two()))
        .run(([127, 0, 0, 1], 3000))
        .await;
}

I've tried using warp:Filter and multiple variations of it, but I haven't found a return type that compiles.

P.S. I know in this example extracting out the filters into their own functions just complicates things, but I have a situation where it may actually simplify things.

Upvotes: 3

Views: 2448

Answers (3)

Ultrasaurus
Ultrasaurus

Reputation: 3169

The following code worked for me -- both your example and my more complex use case. (The other answers were helpful as a starting point, but didn't resolve my issues).

The way I got it to work was by removing async since we don't need function to be async just to generate a filter and it works around the fact that Rust compiler is a little finicky these days for use cases like these:

use warp::Filter;

fn get_route_one() 
-> impl Filter<Extract = (impl warp::Reply + 'static,), Error = warp::Rejection> + Clone  + 'static {

     warp::get().and(warp::path("path1")).map(|| warp::reply())
}

fn get_route_two() 
-> impl Filter<Extract = (impl warp::Reply + 'static,), Error = warp::Rejection> + Clone  + 'static {
     warp::get().and(warp::path("path1")).map(|| warp::reply())
}

#[tokio::main]
async fn main() {
    warp::serve(get_route_one().or(get_route_two()))
        .run(([127, 0, 0, 1], 3000))
        .await;
}

Upvotes: 0

erewok
erewok

Reputation: 7835

This is what we do in our own projects. For instance, we may have an endpoint like this:

pub async fn index(cfg: crate::settings::Settings) -> Result<impl warp::Reply, warp::Rejection> {
    info!("Index endpoint called");
    Ok(warp::reply::with_status(
        format!("Welcome to Our API Version {}", cfg.version),
        http::StatusCode::OK,
    ))
}

And we may have another endpoint like this:

pub async fn health() -> Result<impl warp::Reply, warp::Rejection> {
    Ok(warp::reply::with_status("OK", http::StatusCode::OK))
}

We can build a function that wraps these up like this:

use warp::Filter;

/// External endpoints: /v1/base
pub fn base_endpoints(
    config: crate::settings::Settings,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {

    let base_endpoints_trunk = warp::path("v1").and(warp::path("base"));
    let index = base_endpoints_trunk
        .and(warp::get())
        .and(warp::path::end())
        .and(crate::settings::with_cfg(config.clone()))
        .and_then(index);
    let health = base_endpoints_trunk
        .and(warp::get())
        .and(warp::path("health"))
        .and(warp::path::end())
        .and_then(health);

    index.or(health)
}

Then, inside our main, we can do something like this:

let base = endpoints::base_endpoints(CONFIG.clone());

warp::serve(base.recover(errors::handle_rejection)).run(([0, 0, 0, 0], 9000)).await

Upvotes: 2

isaactfa
isaactfa

Reputation: 6651

It'll depend on your actual types but something in the vicinity of impl Filter<Extract = impl warp::Reply, Error = warp::Rejection>. I'll recommend to check out the todos example for inspiration.

Upvotes: 2

Related Questions