GREsau / schemars

Generate JSON Schema documents from Rust code
https://graham.cool/schemars/
MIT License
791 stars 220 forks source link

Behavior change in 0.8.19 with `default`, `required`, and `skip_serializing_if` #292

Closed ahl closed 3 months ago

ahl commented 4 months ago

We use schemars for our OpenAPI document generation. We have a type with an optional property. With the OpenAPI generation this comes out as nullable:

#[derive(JsonSchema)]
pub struct WithNullable {
    pub value: Option<String>,
}
{
  "type": "object",
  "properties": {
    "value": {
      "type": "string",
      "nullable": true
    }
  }
}

We don't want the nullable in the spec and found prior to 0.8.19 that this combination got what we wanted:

#[derive(JsonSchema)]
pub struct WithoutNullable {
    #[schemars(default, required)]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub value: Option<String>,
}

Which produces this in 0.8.17

{
  "type": "object",
  "properties": {
    "value": {
      "type": "string"
    }
  }
}

However, in 0.8.19 we see this:

{
  "type": "object",
  "required": [
    "value"
  ],
  "properties": {
    "value": {
      "type": "string"
    }
  }
}

Is this behavior change from 0.8.17 to 0.8.19 intentional?

GREsau commented 4 months ago

This is an interesting case, and frankly I'm not 100% sure what the "correct" behaviour here is with this complicated combination of default/required/skip_serializing_if/Option<>.

In any case, I think this does what you want, and works in all versions:

#[derive(JsonSchema)]
pub struct WithoutNullable {
    #[schemars(default, with = "String")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub value: Option<String>,
}

Does that solve your problem?

ahl commented 4 months ago

Sure! Or we can hand roll a JsonSchema impl. I should have been clearer: this behavior changed in a patch release. If that's intended / ok: please close this issue. If it's unintended then perhaps reinstate the behavior and/or change it in a minor release?

GREsau commented 3 months ago

Thanks for reporting this, I've now released 0.8.20 which restores the previous behaviour