Skip to content

schema generation is incomplete #1489

@icefery

Description

@icefery

Overview

when i use a nested type(AppResponse<PlainTreeNode<Category>>) in response, some schemas are missing in the generated openapi.json.

  • AppResponse_PlainTreeNode_Category
  • Category
  • PlainTreeNode_Category (Missing)
openapi.json
{
  "openapi": "3.1.0",
  "info": { "title": "utoipa-axum", "description": "Utoipa's axum bindings for seamless integration for the two", "contact": { "name": "Juha Kukkonen", "email": "[email protected]" }, "license": { "name": "MIT OR Apache-2.0", "identifier": "MIT OR Apache-2.0" }, "version": "0.2.0" },
  "paths": { "/list-category": { "get": { "operationId": "list_category", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AppResponse_PlainTreeNode_Category" } } } } } } } },
  "components": {
    "schemas": {
      "AppResponse_PlainTreeNode_Category": {
        "type": "object",
        "required": ["code", "message"],
        "properties": {
          "code": { "type": "integer", "format": "int64" },
          "data": {
            "type": "object",
            "required": ["key", "children"],
            "properties": { "children": { "type": "array", "items": { "$ref": "#/components/schemas/PlainTreeNode_Category" } }, "data": { "type": "object", "required": ["code", "name"], "properties": { "code": { "type": "string" }, "name": { "type": "string" } } }, "key": { "type": "string" } }
          },
          "message": { "type": "string" }
        }
      },
      "Category": { "type": "object", "required": ["code", "name"], "properties": { "code": { "type": "string" }, "name": { "type": "string" } } }
    }
  }
}

Reproduce

[dependencies]
axum              = { version = "0" }
serde             = { version = "1", features = ["derive"] }
tokio             = { version = "1", features = ["full"] }
utoipa            = { version = "5.4.0", features = ["axum_extras"] }
utoipa-axum       = { version = "0.2.0" }
utoipa-swagger-ui = { version = "9.0.2", features = ["axum", "vendored"] }
#[derive(serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
pub struct AppResponse<T = ()> {
    pub code: i64,
    pub message: String,
    pub data: Option<T>,
}

#[derive(serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
struct PlainTreeNode<T> {
    key: String,
    data: Option<T>,
    #[schema(no_recursion)]
    children: Vec<PlainTreeNode<T>>,
}

#[derive(serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
pub struct Category {
    pub code: String,
    pub name: String,
}

#[utoipa::path(get, path = "/list-category", responses((status = 200, body = AppResponse<PlainTreeNode<Category>>)))]
async fn list_category() -> axum::Json<AppResponse<PlainTreeNode<Category>>> {
    todo!()
}

#[tokio::main]
async fn main() {
    let (router, api) = utoipa_axum::router::OpenApiRouter::new().routes(utoipa_axum::routes!(list_category)).split_for_parts();
    let router = router.merge(utoipa_swagger_ui::SwaggerUi::new("/swagger-ui").url("/api/openapi.json", api));
    let app = router.into_make_service();
    let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await.unwrap();
    axum::serve(listener, app).await.unwrap()
}
cargo run

Try to fix

add the missing type PlainTreeNode<Category> to arg:

#[utoipa::path(get, path = "/list-category", responses((status = 200, body = AppResponse<PlainTreeNode<Category>>)))]
async fn list_category(
    axum::Json(req): axum::Json<PlainTreeNode<Category>>,
) -> axum::Json<AppResponse<PlainTreeNode<Category>>> {
    todo!()
}
openapi.json
{
  "openapi": "3.1.0",
  "info": { "title": "utoipa-axum", "description": "Utoipa's axum bindings for seamless integration for the two", "contact": { "name": "Juha Kukkonen", "email": "[email protected]" }, "license": { "name": "MIT OR Apache-2.0", "identifier": "MIT OR Apache-2.0" }, "version": "0.2.0" },
  "paths": {
    "/list-category": {
      "get": {
        "operationId": "list_category",
        "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlainTreeNode_Category" } } }, "required": true },
        "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AppResponse_PlainTreeNode_Category" } } } } }
      }
    }
  },
  "components": {
    "schemas": {
      "AppResponse_PlainTreeNode_Category": {
        "type": "object",
        "required": ["code", "message"],
        "properties": {
          "code": { "type": "integer", "format": "int64" },
          "data": {
            "type": "object",
            "required": ["key", "children"],
            "properties": { "children": { "type": "array", "items": { "$ref": "#/components/schemas/PlainTreeNode_Category" } }, "data": { "type": "object", "required": ["code", "name"], "properties": { "code": { "type": "string" }, "name": { "type": "string" } } }, "key": { "type": "string" } }
          },
          "message": { "type": "string" }
        }
      },
      "Category": { "type": "object", "required": ["code", "name"], "properties": { "code": { "type": "string" }, "name": { "type": "string" } } },
      "PlainTreeNode_Category": {
        "type": "object",
        "required": ["key", "children"],
        "properties": { "children": { "type": "array", "items": { "$ref": "#/components/schemas/PlainTreeNode_Category" } }, "data": { "type": "object", "required": ["code", "name"], "properties": { "code": { "type": "string" }, "name": { "type": "string" } } }, "key": { "type": "string" } }
      }
    }
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions