GREsau / schemars

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

Enum to oneOf with refs #157

Open tiagoskaneta opened 2 years ago

tiagoskaneta commented 2 years ago

Hello,

Is it possible to make the schema for an enum to use $refs instead of having all the variants in a single oneOf block?

For example, I have the following:

use schemars::{schema_for, JsonSchema};

#[derive(JsonSchema)]
pub struct MyStruct {
    pub my_enum: MyEnum,
}

#[derive(JsonSchema)]
pub enum MyEnum {
    Foo(String),
    Bar(String),
}

fn main() {
    let schema = schema_for!(MyStruct);
    println!("{}", serde_json::to_string_pretty(&schema).unwrap());
}

which outputs:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "MyStruct",
  "type": "object",
  "required": [
    "my_enum"
  ],
  "properties": {
    "my_enum": {
      "$ref": "#/definitions/MyEnum"
    }
  },
  "definitions": {
    "MyEnum": {
      "oneOf": [
        {
          "type": "object",
          "required": [
            "Foo"
          ],
          "properties": {
            "Foo": {
              "type": "string"
            }
          },
          "additionalProperties": false
        },
        {
          "type": "object",
          "required": [
            "Bar"
          ],
          "properties": {
            "Bar": {
              "type": "string"
            }
          },
          "additionalProperties": false
        }
      ]
    }
  }
}

Ideally I would like to have the MyEnum defined as such:

"MyEnum": {
      "oneOf": [
        { "$ref": "#/definitions/MyEnum_Foo" },
        { "$ref": "#/definitions/MyEnum_Bar" },
     ]
}

Thank you in advance.

tomas789 commented 9 months ago

I ran into the same problem while generating OpenAPI specification using aide. The managed to work around this issue and documented all the options I come up with in this issue.

Based on my research your solution would be to use untagged enums.

#[derive(JsonSchema)]
#[serde(untagged)]
pub enum MyEnum {
    Foo(String),
    Bar(String),
}

which would generate (OpenAPI settings)

      "MyEnum": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/Foo"
          },
          {
            "$ref": "#/components/schemas/Bar"
          },
        ],