How do I create a warp path segment from a user provided path?

Hi all,

I would like to create a warp path segment filter from a path that is passed in via configuration. I've not been able to figure out how to make it work yet. I've tried to split the path string, then assemble a path filter by using the iterator methods. However, I've not been able to make heads or tails of the type errors there.

I would like to be able to do this:

// This will be dynamically given as a command line argument or loaded from a file.
let config_provided_path = "/foo/bar/baz"; 

let route1 = warp::get().and(warp::path("cow")).map(|| "Goes moo, moo!");
let route2 = warp::get().and(warp::path("dog")).map(|| "Goes woof, woof!");
let route3 = warp::get().and(warp::path("cat")).map(|| "Goes meow!");

let routes = warp::path(config_provided_path).and(route1.or(route2).or(route3));

warp::serve(routes).run(bind_address).await;

Is there a known way to do this?

What's the desired outcome? Are you trying to have that config path available to the filters (ie available to the map functions in the example)? Or are you just trying to serve files from those folders?

The desired outcome is to have the routes ("cow", "dog", "cat") served at the path provided by the configuration. In my example this would mean:

GET /foo/bar/baz/cow

GET /foo/bar/baz/dog

GET /foo/bar/baz/cat

Would be the valid requests to the service implemented by my example code.

I don't require the path within my handler code, just that the handlers are mounted using the path provided by the configuration string.

Ahh. So here's one way to do it that's not the most efficient but it works. The trick that i used was to use boxed() which basically hides the type behind a pointer. Otherwise every call to and(..) creates a new type which wraps the previous one which leads to issues and a series of potentially difficult error messages to follow. warp doesn't expose a bunch of its internals, so i don't immediately see a simple solution that's more efficient.

    let bind_address: std::net::SocketAddrV4 = "127.0.0.1:8000".parse().unwrap();
    // This will be dynamically given as a command line argument or loaded from a file.
    let config_provided_path = "/foo/bar/baz";
    let base = config_provided_path
        .split('/')
        .skip_while(|p| p.is_empty())
        .fold(warp::any().boxed(), |f, path| {
            f.and(warp::path(path)).boxed()
        });

    let route1 = warp::get().and(warp::path("cow")).map(|| "Goes moo, moo!");
    let route2 = warp::get()
        .and(warp::path("dog"))
        .map(|| "Goes woof, woof!");
    let route3 = warp::get().and(warp::path("cat")).map(|| "Goes meow!");

    let routes = base.and(route1.or(route2).or(route3));

    warp::serve(routes).run(bind_address).await;
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.