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

Using sea-orm model as body type generates incorrect schema name #435

Closed
112RG opened this issue Jan 13, 2023 · 4 comments
Closed

Using sea-orm model as body type generates incorrect schema name #435

112RG opened this issue Jan 13, 2023 · 4 comments

Comments

@112RG
Copy link

112RG commented Jan 13, 2023

When using a sea-orm Model as a return type causes the schema generation to break and name the components.schema incorrectly

My utoipa route macro

#[utoipa::path(
    get,
    path = "/artists/{id}",
    params(
        ("id" = String, Path, description = "Artist Id")
    ),
    responses(
        (status = 200, description = "List containing albums", body = [entity::album::Model])
    )
)]

Here is my Model struct

#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize, ToSchema)]
#[sea_orm(table_name = "artists")]
pub struct Model {
    #[sea_orm(primary_key, auto_increment = false)]
    pub id: String,
    #[sea_orm(unique)]
    pub name: String,
    pub image: Option<String>,
    pub bio: Option<String>,
    #[sea_orm(column_name = "createdAt")]
    pub created_at: String,
    #[sea_orm(column_name = "updatedAt")]
    pub updated_at: String,
}

And finally here is my generation

    #[derive(OpenApi)]
    #[openapi(
        paths(
            deaftone::handlers::albums::get_albums,
            deaftone::handlers::albums::get_album,
            deaftone::handlers::artists::get_artists,
            deaftone::handlers::artists::get_artist
        ),
        components(
            schemas(
                deaftone::handlers::albums::GetAllAlbumsQuery,
                deaftone::handlers::albums::AlbumResponse,
                entity::album::Model,
                deaftone::handlers::artists::GetArtistsQuery,
                entity::artist::Model,
            )
        ),
        tags(
            (name = "deaftone", description = "Deaftone API")
        )
    )]

All sea-orm entities must have a struct called Model. When generating the json file. The Model struct is outputted as

"components": {
    "schemas": {
      "Model": {

And the schema json is generated as so

        "responses": {
          "200": {
            "description": "List containing artists",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/entity.artist.Model"
                  }
                }
              }
            }
          }
        }

Which leads to swagger or in my case docusaurus-preset-openapi failing to find the schema definition. There is also another problem when you start adding multiple Model structs it wont work since they are always outputted as Model

@112RG
Copy link
Author

112RG commented Jan 24, 2023

@juhaku might of missed this

@juhaku
Copy link
Owner

juhaku commented Jan 25, 2023

Yeah, sorry for late reply. @112RG

There is one thing that should help you with this:

// ... in albums list api
responses(
    (status = 200, description = "List containing albums", body = [entity::album::Model])
)

// ... in users list api
responses(
    (status = 200, description = "List containing albums", body = [entity::user::Model])
)

Then where the ApiDoc is being generated you can use as .... statement to change the name of the model. This then would generate the model as entity.user.Model and entity.album.Model which will match to the name referenced from endpoints defined above.

 components(
    schemas(
        entity::album::Model as entity::album::Model,
        entity::user::Model as entity::user::Model,
    )
),

As a matter of fact I might just change this behavior for the next release the otherway around in a way that the schemas(...) declaration would behave the same way as within utoipa::path(... responses(...) ) that the name will be created from the full path and and not just of last fragment like it is done now.

@juhaku
Copy link
Owner

juhaku commented Jan 26, 2023

I changed the behavior for the next release and now it is better and more clear. More details here: #459.

Basically now you can register types having same name to OpenAPI as follows. as attribute can be used to define alternative name / path to the schema which will be used to register the schema into OpenAPI spec. The value must match to the path what is being used for responses body or request_body.

#[derive(ToSchema)]
#[schema(as = entity::album::Model)]
struct Model {
    id: String
}

#[derive(ToSchema)]
#[schema(as = entity::artist::Model)]
struct Model {
    id: String
}

// .. then in the handler

#[utoipa::path(
    get,
    path = "/artists",
    responses(
        (status = 200, description = "List artists", body = [entity::artist::Model])
    )
)]
async fn get_artists() -> Vec<entity::artists::Model> {
    Vec::new()
}


// .. and where ever the types are registered to the OpenAPI

#[derive(OpenApi)]
#[openapi(
    components(
        schemas(entity::artist::Model, entity::album::Model)
    )
)]
struct ApiDoc;

@juhaku
Copy link
Owner

juhaku commented Feb 15, 2023

Related: #230

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants