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

Schema title not supported on basic enums #954

Closed
scrous opened this issue Jun 3, 2024 · 3 comments
Closed

Schema title not supported on basic enums #954

scrous opened this issue Jun 3, 2024 · 3 comments

Comments

@scrous
Copy link

scrous commented Jun 3, 2024

I would like to add some title descriptions to enum values, however it only works on enum structs not basic enum values.

For example, if I try this:

#[derive(ToSchema)]
pub enum SomeEnum {
    #[schema(title="title")]
    A,
    B,
    C
}

I get unexpected attribute: title, expected any of: rename

But if I have:

#[derive(ToSchema)]
pub enum SomeEnum {
    #[schema(title="title")]
    A,
    B(String),
    C
}

Then I get the following options: any of: title, rename_all, rename, example

Would it be possible to add title to the first example. We have a list of abbreviations as enums and it would be helpful to add what each field means.

@juhaku
Copy link
Owner

juhaku commented Aug 19, 2024

Sure, can be added. Also PR:s are welcome.

@juhaku juhaku added the enhancement New feature or request label Aug 19, 2024
@juhaku juhaku removed the enhancement New feature or request label Aug 24, 2024
@juhaku juhaku removed this from utoipa kanban Aug 24, 2024
@juhaku
Copy link
Owner

juhaku commented Aug 24, 2024

@scrous As I took a further look on this matter. It is not possible because unit type enums are represented in OpenAPI as enums known to OpenAPI spec and JSON schema. See here: https://json-schema.org/understanding-json-schema/reference/enum.

That is the enum typically is a single value of predefined constants but in Rust this this not necessary the case. Thus the so called complex enum type does translate to OpenAPI OneOf type which in itself does support different kind of attributes.

In order to achieve this functionality there would be a need to completely change the representation of the enum based on presence of the title attribute which is not very feasible.

@juhaku juhaku closed this as completed Aug 24, 2024
@scrous
Copy link
Author

scrous commented Aug 26, 2024

@juhaku Thanks for looking into this.
Ah okay, that is unfortunate, I see there has been much discussion around this topic: json-schema-org/json-schema-spec#57 , but the only current solution is to use oneOf + const, which will need a big rework.

However, then I found this recommending putting the information in the enum's description. https://swagger.io/docs/specification/data-models/enums/ which looks like a nicer workaround, without impacting the enum.

I think this can remain closed. But here is a workaround for displaying the enum descriptions in the description if someone stumbles on this issue:
You need itertools and strum for this to work, you can also replace enum debug + format with strum display

use itertools::Itertools;
use serde_json::json;
use strum::{EnumMessage, IntoEnumIterator};
use strum_macros::{EnumIter, EnumMessage};
use utoipa::openapi::ObjectBuilder;

#[derive(EnumIter, EnumMessage, Debug)]
pub enum SomeEnum {
    #[strum(message = "Alpha")]
    A,
    #[strum(message = "Bravo")]
    B,
    #[strum(message = "Charlie")]
    C,
}

impl<'__s> utoipa::ToSchema<'__s> for SomeEnum {
    fn schema() -> (
        &'__s str,
        utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>,
    ) {
        let values = SomeEnum::iter()
            .map(|v| (format!("{v:?}"), v.get_message().unwrap_or("")))
            .collect::<Vec<_>>();

        let descriptions = values
            .iter()
            .map(|(v, description)| format!("* {v} - {description}"))
            .join(" \n ");

        (
            "SomeEnum",
            ObjectBuilder::new()
                .schema_type(utoipa::openapi::SchemaType::String)
                .description(Some(format!("List of possible values: \n {descriptions}")))
                .enum_values(Some(values.into_iter().map(|(v, _)| v)))
                .into(),
        )
    }
}

Which outputs as follows using scalar:
image

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