Organizing Warp Routes / Discovering Return Types

Hello, I've been trying to write a web app using Warp. What I'd like to have is a function that returns routes that I can chain to the end of some other route, so it's portable and separated.

fn mixin_kubernetes_routes() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    let index_path = warp::path::end()
        .map(|| "Kubernetes Index");

    let namespaces_path = warp::path!("namespaces")
        .map(|| "Namespaces");

    index_path.or(namespaces_path)
}

I stole the return type from the todos example app: https://github.com/seanmonstar/warp/blob/master/examples/todos.rs . Unfortunately when I try and chain it using something like:

    // The goal is to mount everything under /kubernetes/*
    let kubernetes_root = warp::path("kubernetes")
        .and(mixin_kubernetes_routes());

I get:

error[E0277]: the trait bound `impl warp::Reply: warp::generic::Tuple` is not satisfied
  --> src/main.rs:37:10
   |
37 |         .and(mixin_kubernetes_routes());
   |          ^^^ the trait `warp::generic::Tuple` is not implemented for `impl warp::Reply`

This trait it's complaining about is private. Is there a way to do what I want or is there a better way to organize routes in a composable way? Thanks for the help.

I guess to clairify the problem, the following works:

    let index_path = warp::path::end()
        .map(|| "Kubernetes Index");

    let namespaces_path = warp::path!("namespaces")
        .map(|| "Namespaces");

    let index_or_namespaces = index_path.or(namespaces_path);

    // The goal is to mount everything under /kubernetes/*
    let kubernetes_root = warp::path("kubernetes")
        .and(index_or_namespaces);

All I want to do is have a function that returns the index_or_namespaces object so that I can move that logic elsewhere. I don't know what the return type of this function should be or how to discover it. Thanks!

This issue looks like the same thing you're running into: https://github.com/seanmonstar/warp/issues/646

TL;DR: The Extract type of a filter always has to be a tuple, even if your filter only extracts a single value. This means that you need to write Extract = (impl warp::Reply,) instead of Extract = impl warp::Reply .

This is due to some type magic that Warp uses behind the scenes to flatten closure arguments.

1 Like

That did indeed work, thank you very much. Is there any way to discover the working return types I should be using or do I just kind of have to hope its documented or commented on somewhere? I'm just wondering what I'm missing in my brain that would allow me to solve these kinds of problems in the future!

I must admit, I've got absolutely no clue why impl Reply works for that todos example and not your code - Warp's heavy use (abuse?) of the type system makes this kind of thing very complicated!

1 Like

Alright well that makes me feel a little better knowing that this isn't some trivial obvious thing that my mental model of Rust was just broken with! Thank you for your help.

1 Like