utoipa icon indicating copy to clipboard operation
utoipa copied to clipboard

OpenAPI not being served according to Actix scopes

Open JasterV opened this issue 1 year ago • 4 comments

Hi!

I'm trying to expose an OpenAPI spec this way:

...
.service(
    web::scope("/docs")
        .wrap(auth)
        .service(
            SwaggerUi::new("/swagger-ui/{_:.*}").url("/api-doc/openapi.json", openapi.clone()),
))

The problem is that when navigating to localhost:8000/docs/swagger-ui we get the following error:

screenshot_2022-09-14_at_11 24 17

And the reason is that the openapi.json is now under /docs/api-doc/openapi.json but by default the UI tries to point to /api-doc/openapi.json.

In fact, if I search on the bar for /docs/api-doc/openapi.json it renders the correct page

JasterV avatar Sep 14 '22 09:09 JasterV

In general the scopes are quite hard topic, and most likely there is some room to improve. It's just a really hard nut to crack since the web libraries are not exposing the context path or scope outside.

As what comes to the example, the SwaggerUi::new(...) expects a relative path from root of the app and similarly the .url(...) method does.

SwaggerUi::new("/swagger-ui/{_:.*}").url("/api-doc/openapi.json", openapi.clone())

For what comes to scopes now maybe this example might help you: https://github.com/juhaku/utoipa/tree/master/examples/actix-web-multiple-api-docs-with-scopes

And there is an old issue regarding the sopes as well: https://github.com/juhaku/utoipa/issues/121 And also there is this PR https://github.com/juhaku/utoipa/pull/274 which is still unresolved but concerning axum framework but concerns same topic and actually if something will be done then the changes here should be also done for actix-web and rocket framework's as well.

juhaku avatar Sep 14 '22 11:09 juhaku

@juhaku Thank you, I'm going to try the example

As a workaround, I've done this:

// On the server
web::scope("/docs")
     .wrap(HttpAuthentication::basic(validator))
     .route(
         "/openapi.json",
          web::get().to(crate::controller::open_api_spec),
      )
      .service(
          SwaggerUi::new("swagger/{_:.*}")
          .url("/docs/openapi.json", Default::default()),
);

// open_api_spec
pub async fn open_api_spec(_: web::Data<ServerData>) -> HttpResponse<BoxBody> {
    let openapi = ApiDoc::openapi();
    HttpResponse::Ok().json(openapi)
}

And it actually works :smile: The idea is to expose the json file on a separate route and then point to it with the SwaggerUI service. But this is a bit tricky and we are exposing a dummy default OpenAPI spec

JasterV avatar Sep 14 '22 12:09 JasterV

@juhaku The example did not work for us as what we want is to modify the endpoint where the json file is served, that is a bit different from what is being done in the example which is related to modifying the base endpoint of the exposed paths.

I hope it makes sense 😵‍💫 hahah

Thank you anyway!

JasterV avatar Sep 14 '22 15:09 JasterV

Aa yeah, I see.. So you would like to have custom functionality over the handler of the OpenAPI doc endpoint? If I get you right :smile: That is indeed not supported via the SwaggerUi struct unfortunately since that actually creates simple handlers behind the scenes without offering capability to enhance them in anyways. One alternative is to look the warp or tide example (you can find them in the examples folder) of how to implement the manual serving of Swagger UI and OpenAPI doc.

That is something that could be added in future indeed, but needs some desing thinking for to get it right. And in tandem the support should also be added for all the frameworks like axum and rocket not just actix-web.

juhaku avatar Sep 14 '22 16:09 juhaku