utoipa icon indicating copy to clipboard operation
utoipa copied to clipboard

Automatic type recognition for path operation handlers

Open juhaku opened this issue 2 years ago • 7 comments

Description

To streamline further the utoipa library and to provide deeper integeration for frameworks like actix_web, axum, and rocket it would be great to be able to automatically recognize necessary types from operation handler and add them to the path schema of OpenAPI doc generated with utoipa. This will provide more automation and saves the keystrokes the user is ought to take to define #[utoipa::path(...)] macro content manually.

For example, from following handler function we would need to be able to recognize path, query, body and response. These recognized values, if successful, should be added automatically to the generated OpenAPI spec.

#[utoipa::path]
async fn post_item(path: Path<PathParams>, query: Query<QueryParams>, item: Json<ItemBody>) -> Response {
    Response::Success(Item { value: "super".to_string() })
}

This functionality will enforce users to be more strict on what is being returned from the handler functions and what are the args given to the handler functions. Benefit of this is the users are able to declare the OpenAPI spec mostly via code and get compile errors directly to the code of invalid spec.

Tasks

  • [x] Implement general response body recognition - All responses need to implement IntoResponses trait.
  • [ ] Implement response body recognition for actix_web
  • [ ] Implement response body recognition for axum
  • [ ] Implement response body recognition for rocket
  • [x] Implement request body recognition for actix_web
  • [x] Implement request body recognition for axum
  • [x] Implement request body recognition for rocket
  • [x] Enhance current path and query parameter support in actix_web to support auto recognition
  • [x] Enhance current path and query parameter support in axum to support auto recognition
  • [x] Enhance current path and query parameter support in rocket to support auto recognition

juhaku avatar Apr 18 '23 22:04 juhaku

I think related; it was really surprising (in axum) that Path<(X, Y)> would auto generate the path params but Path<X> does not

TheDan64 avatar Apr 27 '23 20:04 TheDan64

Yeah, I can take a look at this at the same time.

juhaku avatar Apr 28 '23 06:04 juhaku

Any ideas are welcome to this one https://github.com/juhaku/utoipa/pull/649. Currently not sure at the moment how to proceed with the implementation. The biggest issue is that if I have a handler such as seen below, I can only resolve responses for Result type based on assumtions without the possibility to realiably change / override or ignore them later on. This practically becomes quite limiting if we assume that the responses from the given handler were only 200 for success and default for any possible error. Sure we can add more responses with the responses(...) attribute in utoipa::path macro, but we cannot map them reliably with the auto-resolved ones.

#[utoipa::path]
#[get("/item")]
async fn get_item() -> Result<Json<Item<'static>>, Error> {
    Ok(Json(Item { value: "super" }))
}

juhaku avatar Jun 12 '23 20:06 juhaku

I think related; it was really surprising (in axum) that Path<(X, Y)> would auto generate the path params but Path<X> does not

@TheDan64 This PR #668 should fix the issue in the path parameters.

juhaku avatar Jul 09 '23 17:07 juhaku

@juhaku thanks! is this in 3.4.3? I seem to be having the same issue still

TheDan64 avatar Jul 25 '23 15:07 TheDan64

@juhaku thanks! is this in 3.4.3? I seem to be having the same issue still

Here is some more examples how the path parameter can be recognized: https://github.com/juhaku/utoipa/commit/7cc90b142f4404144d36effd38afd09a60c86a85.

It is not fully automatic because the original behavior was reverted as it caused unwanted issues for many users. There is some work to do for make this implementation better but for what comes to the axum path parameters the name of the handler argument must match to the path arguments otherwise they will not be added.

    // `id` must match to the path argument name.
    async fn get_item(id: Path<u32>) {}
    
    // `id and `id2` must match to the path argument name.
    async fn get_item(Path((id, id2)): Path<(u32, u32)>) {}

juhaku avatar Aug 03 '23 16:08 juhaku