Search code examples
rustrust-poem

rust poem route with variable path segments


I have an HTTP endpoint in rust using poem::openapi. I would like a single handler for a variable segment path.

#[OpenApi]
impl NvApi {
    #[oai(path = "/:namespace/:id", method = "get")]
    async fn get(
        &self,
        nv: Data<&SharedHandle>,
        namespace: Path<String>,
        id: Path<String>,
    ) -> Result<GetResponse, poem::Error> {
        log::debug!("get {}/{}", namespace.as_str(), id.as_str());
...
...
...
}

I would like the code above to handle paths like /mynamespace/mydomain/myid as well as /mynamespace/myid - an arbitrary number of segments loaded into the namespace variable but always loading the trailing segment into the 'id' variable.

I've seen references to "*path" in the poem repo but can't find any docs or examples of wildcard. I'd like to use the pattern above as my SharedHandle impl is needed.


Solution

  • This is not directly possible.

    The path parser in poem breaks after encountering a wildcard token which means it cannot be used to match in the middle of a path.

    The best workaround would be to use a regex that matches all path segments except the final segment. In code, that would hypothetically appear as:

        #[oai(path = "/:namespace<.+(?=/)>/:id", method = "get")]
        async fn get(&self, ...) ...
    

    but poem uses the regex crate which does not support lookaheads (needed to ignore the last slash).

    Instead, you will have to use a regex with no lookaheads and manually remove the trailing slash:

    #[OpenApi]
    impl Api {
        #[oai(path = "/:namespace<.+/>:id", method = "get")]
        async fn get(
            &self,
            ...
            namespace: Path<String>,
            id: Path<String>,
        ) -> ... {
            // GET /a/b/c
            println!("{}", namespace.to_string()); // a/b/
            println!("{}", id.to_string());        // c
            ...
        }
    }