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

Subschema inlining on Newtype enums even with latest changes. #356

Closed
bralax opened this issue Dec 1, 2024 · 2 comments
Closed

Subschema inlining on Newtype enums even with latest changes. #356

bralax opened this issue Dec 1, 2024 · 2 comments

Comments

@bralax
Copy link

bralax commented Dec 1, 2024

@GREsau With regards to #355 and #347, even on the latest alpha (1.0.0-alpha.16), I'm still seeing all subschemas getting inlined.

For example, using this code as my test:

use schemars::{generate::SchemaSettings, JsonSchema};

#[derive(JsonSchema)]
#[serde(tag = "type")]
pub enum Root {
    A(SubEnum1),
    B(SubEnum2),
}

#[derive(JsonSchema)]
#[serde(tag = "other_type")]
pub enum SubEnum1 {
    C(SubSchema1),
    D(SubSchema2),
}

#[derive(JsonSchema)]
#[serde(tag = "other_type")]
pub enum SubEnum2 {
    E(SubSchema3),
    F(SubSchema4),
    G(String),
    H{id: String}
}

#[derive(JsonSchema)]
pub struct SubSchema1 {
    pub w: String,
}

#[derive(JsonSchema)]
pub struct SubSchema2 {
    pub x: String,
}

#[derive(JsonSchema)]
pub struct SubSchema3 {
    pub y: String,
}

#[derive(JsonSchema)]
pub struct SubSchema4 {
    pub z: String,
}

fn main() {
    let mut settings = SchemaSettings::draft2020_12();
    settings.inline_subschemas = false;
    let schema = settings.into_generator().root_schema_for::<Root>();
    println!("{}", serde_json::to_string_pretty(&schema).unwrap());
}

I get the following schema:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Root",
  "oneOf": [
    {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "A"
        }
      },
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "other_type": {
              "type": "string",
              "const": "C"
            },
            "w": {
              "type": "string"
            }
          },
          "required": [
            "other_type",
            "w"
          ]
        },
        {
          "type": "object",
          "properties": {
            "other_type": {
              "type": "string",
              "const": "D"
            },
            "x": {
              "type": "string"
            }
          },
          "required": [
            "other_type",
            "x"
          ]
        }
      ],
      "required": [
        "type"
      ]
    },
    {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "B"
        }
      },
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "other_type": {
              "type": "string",
              "const": "E"
            },
            "y": {
              "type": "string"
            }
          },
          "required": [
            "other_type",
            "y"
          ]
        },
        {
          "type": "object",
          "properties": {
            "other_type": {
              "type": "string",
              "const": "F"
            },
            "z": {
              "type": "string"
            }
          },
          "required": [
            "other_type",
            "z"
          ]
        },
        {
          "type": "object",
          "properties": {
            "other_type": {
              "type": "string",
              "const": "G"
            }
          },
          "required": [
            "other_type"
          ]
        },
        {
          "type": "object",
          "properties": {
            "id": {
              "type": "string"
            },
            "other_type": {
              "type": "string",
              "const": "H"
            }
          },
          "required": [
            "other_type",
            "id"
          ]
        }
      ],
      "required": [
        "type"
      ]
    }
  ]
}

This schema does not end up with any definitions section and every model and enum other than Root is inlined. In this case also nothing is marked as deny_unknown_fields so it shouldn't be falling into that edge case.

@GREsau
Copy link
Owner

GREsau commented Dec 2, 2024

That's odd - it looks like the changes around internally-tagged newtype variants weren't actually included in the published crate. It's possible I forgot to update my local master branch before publishing...

I've now published v1.0.0-alpha.17, which definitely does include the change! In this version, the output from your example is:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Root",
  "oneOf": [
    {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "A"
        }
      },
      "$ref": "#/$defs/SubEnum1",
      "required": [
        "type"
      ]
    },
    {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "B"
        }
      },
      "$ref": "#/$defs/SubEnum2",
      "required": [
        "type"
      ]
    }
  ],
  "$defs": {
    "SubEnum1": {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "other_type": {
              "type": "string",
              "const": "C"
            }
          },
          "$ref": "#/$defs/SubSchema1",
          "required": [
            "other_type"
          ]
        },
        {
          "type": "object",
          "properties": {
            "other_type": {
              "type": "string",
              "const": "D"
            }
          },
          "$ref": "#/$defs/SubSchema2",
          "required": [
            "other_type"
          ]
        }
      ]
    },
    "SubEnum2": {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "other_type": {
              "type": "string",
              "const": "E"
            }
          },
          "$ref": "#/$defs/SubSchema3",
          "required": [
            "other_type"
          ]
        },
        {
          "type": "object",
          "properties": {
            "other_type": {
              "type": "string",
              "const": "F"
            }
          },
          "$ref": "#/$defs/SubSchema4",
          "required": [
            "other_type"
          ]
        },
        {
          "type": "object",
          "properties": {
            "other_type": {
              "type": "string",
              "const": "G"
            }
          },
          "required": [
            "other_type"
          ]
        },
        {
          "type": "object",
          "properties": {
            "id": {
              "type": "string"
            },
            "other_type": {
              "type": "string",
              "const": "H"
            }
          },
          "required": [
            "other_type",
            "id"
          ]
        }
      ]
    },
    "SubSchema1": {
      "type": "object",
      "properties": {
        "w": {
          "type": "string"
        }
      },
      "required": [
        "w"
      ]
    },
    "SubSchema2": {
      "type": "object",
      "properties": {
        "x": {
          "type": "string"
        }
      },
      "required": [
        "x"
      ]
    },
    "SubSchema3": {
      "type": "object",
      "properties": {
        "y": {
          "type": "string"
        }
      },
      "required": [
        "y"
      ]
    },
    "SubSchema4": {
      "type": "object",
      "properties": {
        "z": {
          "type": "string"
        }
      },
      "required": [
        "z"
      ]
    }
  }
}

@GREsau GREsau closed this as completed Dec 2, 2024
@GREsau
Copy link
Owner

GREsau commented Dec 2, 2024

Oh by the way, the schema for the SubEnum2::G(String) variant doesn't really make sense because the variant itself can't be serialized (the variant tag can't be set as a property inside a string). Trying to serialize it causes a runtime error from serde: cannot serialize tagged newtype variant SubEnum2::G containing a string

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