Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[poem-openapi] Path parameters in prefix_path do not generate the correct openapi specification #826

Open
Zstorm999 opened this issue May 31, 2024 · 2 comments
Labels
bug Something isn't working

Comments

@Zstorm999
Copy link

Hello !

I have an api specification of the form :

#[OpenApi(prefix_path="/hello/:name")]
impl Api {
    #[oai(path = "/:surname", method = "get")]
    async fn get(...) -> ... { ... }
}

Note that I have path parameters in both prefix_path and path.

Expected Behavior

I expect the parameter name to be included in the api spec, so the generated spec should be something like

"paths": {
    "/hello/{name}/{surname}": {
      "get": {
        "parameters": [
          {
            "name": "name",
            ...
          },
          {
            "name": "surname",
            ...
          }
        ],
}}}

Actual Behavior

Instead, what is being generated is

"paths": {
    "/hello/:name/{surname}": {
      "get": {
        "parameters": [
          {
            "name": "name",
            ...
          },
          {
            "name": "surname",
            ...
          }
        ],
}}}

This causes problems with api viewers (tested with redoc and swagger-ui), as they do not generate the correct request.

Expected:

curl -X GET http://localhost/api/hello/myname/mysurname

Actual

curl -X GET http://localhost/api/hello/:name/mysurname

Additional testing

For the record, I tested the following api construction in Rust:

#[OpenApi(prefix_path="/hello/{name}")]
impl Api {
    #[oai(path = "/:surname", method = "get")]
    async fn get(...) -> ... { ... }
}

This generates the correct specification, but poem is then unable to correctly use the route and I get a 404 error when trying to access it.

Specifications

  • Version: poem 3.0.1, poem-openapi 5.0.2
  • Platform: tested on MacOS and Linux (probably platform independant)
  • Subsystem: poem-openapi
Full code example
use poem::{listener::TcpListener, Route, Server};
use poem_openapi::{param::{Path, Query}, payload::PlainText, OpenApi, OpenApiService};

struct Api;

#[OpenApi(prefix_path="/hello/:name")]
impl Api {
    #[oai(path = "/:surname", method = "get")]
    async fn index(&self, name: Path<String>, surname: Path<String>) -> PlainText<String> {
        let name = name.0;
        let surname = surname.0;
        PlainText(format!("hello, {name} {surname}!"))
    }
}

#[tokio::main]
async fn main() -> Result<(), std::io::Error> {
    if std::env::var_os("RUST_LOG").is_none() {
        std::env::set_var("RUST_LOG", "poem=debug");
    }
    tracing_subscriber::fmt::init();

    let api_service =
        OpenApiService::new(Api, "Hello World", "1.0").server("http://localhost:3000/api");


    let ui = api_service.swagger_ui();
    let spec = api_service.spec();

    println!("{}", spec);

    Server::new(TcpListener::bind("0.0.0.0:3000"))
        .run(Route::new().nest("/api", api_service).nest("/", ui))
        .await
}
@Zstorm999 Zstorm999 added the bug Something isn't working label May 31, 2024
@Zstorm999
Copy link
Author

Zstorm999 commented Jun 4, 2024

So I found the problem at this line:

let prefix_path = &api_args.prefix_path;

When the full path is generated below, no conversion is applied to the prefix_path, only to the oai_path. This means the path is half-standardized in the final output.

@Zstorm999
Copy link
Author

Zstorm999 commented Oct 1, 2024

So I searched a bit for this problem. There is indeed no generated oai path for the prefix_path attribute. However, due to this line:

#[darling(default, with = "crate::utils::preserve_str_literal")]
prefix_path: Option<Expr>,

The prefix_path can actually be a variable, and not just a string literal. This makes it impossible to validate that path unless a breaking change is introduced requirering it to be a string literal just like the regular path.

There is already a test for this case:

const PREFIX: &str = "/hello2";
struct Api2;
#[OpenApi(prefix_path = PREFIX)]
impl Api2 {
#[oai(path = "/world", method = "get")]
async fn test(&self) {}
#[oai(path = "/", method = "get")]
async fn test1(&self) {}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant