Skip to content

Commit

Permalink
Fix enum titles (#103)
Browse files Browse the repository at this point in the history
  • Loading branch information
rlebran authored Jun 29, 2024
2 parents 317cee1 + 46a961c commit 1f28274
Show file tree
Hide file tree
Showing 3 changed files with 323 additions and 0 deletions.
2 changes: 2 additions & 0 deletions apistos-gen-test/src/tests/api_component_derive_oas_3_1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,7 @@ fn api_component_derive_named_enums_deep() {
json!({
"oneOf": [
{
"title": "something",
"type": "object",
"properties": {
"type": {
Expand All @@ -892,6 +893,7 @@ fn api_component_derive_named_enums_deep() {
]
},
{
"title": "other",
"type": "object",
"properties": {
"type": {
Expand Down
3 changes: 3 additions & 0 deletions apistos-models/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ serde = { workspace = true }
serde_json = { workspace = true }
log = { workspace = true }

[dev-dependencies]
assert-json-diff = { workspace = true }

[features]
deserialize = []
test = []
Expand Down
318 changes: 318 additions & 0 deletions apistos-models/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ impl ApistosSchema {
sch_obj.entry("title").or_insert_with(|| prop_name.clone().into());
}
}
} else if let Some(_type) = props.get("type").and_then(|v| v.as_object()) {
if let Some(Value::String(prop_name)) = _type.get("const") {
sch_obj.entry("title").or_insert_with(|| prop_name.clone().into());
}
}
} else if let Some(enum_values) = sch_obj.clone().get_mut("enum").and_then(|v| v.as_array_mut()) {
if enum_values.len() == 1 {
Expand All @@ -111,3 +115,317 @@ impl From<Schema> for crate::reference_or::ReferenceOr<ApistosSchema> {
Self::Object(value.into())
}
}

#[cfg(test)]
mod test {
use assert_json_diff::assert_json_eq;

use crate::{ApistosSchema, JsonSchema, OpenApiVersion};
use schemars::gen::SchemaSettings;
use serde::Serialize;
use serde_json::json;

#[test]
#[allow(dead_code, unused_qualifications)]
fn test_apistos_schema_transform_3_0() {
#[derive(JsonSchema, Serialize)]
struct TestStruct {
name: String,
}

#[derive(JsonSchema, Serialize)]
struct TestStruct2 {
surname: String,
}

#[derive(JsonSchema)]
enum TestEnum {
Test,
Test2,
}

#[derive(JsonSchema, Serialize)]
#[serde(tag = "type")]
enum TestAlgebraicEnum {
Test { key: String, value: String },
Test2 { key2: String, value2: String },
}

#[derive(JsonSchema, Serialize)]
#[serde(tag = "type")]
enum TestAlgebraicEnum2 {
Test(TestStruct),
Test2(TestStruct2),
}

let mut gen = SchemaSettings::openapi3().into_generator();
let schema = TestEnum::json_schema(&mut gen);

let apistos_schema = ApistosSchema::new(schema, OpenApiVersion::OAS3_0);

assert_json_eq!(
apistos_schema.into_inner(),
json!({
"type": "string",
"enum": [
"Test",
"Test2"
]
})
);

let mut gen = SchemaSettings::openapi3().into_generator();
let schema = TestAlgebraicEnum::json_schema(&mut gen);

let apistos_schema = ApistosSchema::new(schema, OpenApiVersion::OAS3_0);

assert_json_eq!(
apistos_schema.into_inner(),
json!({
"oneOf": [
{
"title": "Test",
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "Test"
},
"key": {
"type": "string"
},
"value": {
"type": "string"
}
},
"required": [
"type",
"key",
"value"
]
},
{
"title": "Test2",
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "Test2"
},
"key2": {
"type": "string"
},
"value2": {
"type": "string"
}
},
"required": [
"type",
"key2",
"value2"
]
}
]
})
);

let mut gen = SchemaSettings::openapi3().into_generator();
let schema = TestAlgebraicEnum2::json_schema(&mut gen);

let apistos_schema = ApistosSchema::new(schema, OpenApiVersion::OAS3_0);

assert_json_eq!(
apistos_schema.into_inner(),
json!({
"oneOf": [
{
"title": "Test",
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "Test"
},
"name": {
"type": "string"
}
},
"required": [
"type",
"name"
]
},
{
"title": "Test2",
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "Test2"
},
"surname": {
"type": "string"
}
},
"required": [
"type",
"surname"
]
}
]
})
);
}

#[test]
#[allow(dead_code, unused_qualifications)]
fn test_apistos_schema_transform_3_1() {
#[derive(JsonSchema, Serialize)]
struct TestStruct {
name: String,
}

#[derive(JsonSchema, Serialize)]
struct TestStruct2 {
surname: String,
}

#[derive(JsonSchema)]
enum TestEnum {
Test,
Test2,
}

#[derive(JsonSchema, Serialize)]
#[serde(tag = "type")]
enum TestAlgebraicEnum {
Test { key: String, value: String },
Test2 { key2: String, value2: String },
}

#[derive(JsonSchema, Serialize)]
#[serde(tag = "type")]
enum TestAlgebraicEnum2 {
Test(TestStruct),
Test2(TestStruct2),
}

let mut gen = SchemaSettings::draft2020_12().into_generator();
let schema = TestEnum::json_schema(&mut gen);

let apistos_schema = ApistosSchema::new(schema, OpenApiVersion::OAS3_1);

assert_json_eq!(
apistos_schema.into_inner(),
json!({
"type": "string",
"enum": [
"Test",
"Test2"
]
})
);

let mut gen = SchemaSettings::draft2020_12().into_generator();
let schema = TestAlgebraicEnum::json_schema(&mut gen);

let apistos_schema = ApistosSchema::new(schema, OpenApiVersion::OAS3_1);

assert_json_eq!(
apistos_schema.into_inner(),
json!({
"oneOf": [
{
"title": "Test",
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "Test"
},
"key": {
"type": "string"
},
"value": {
"type": "string"
}
},
"required": [
"type",
"key",
"value"
]
},
{
"title": "Test2",
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "Test2"
},
"key2": {
"type": "string"
},
"value2": {
"type": "string"
}
},
"required": [
"type",
"key2",
"value2"
]
}
]
})
);

let mut gen = SchemaSettings::draft2020_12().into_generator();
let schema = TestAlgebraicEnum2::json_schema(&mut gen);

let apistos_schema = ApistosSchema::new(schema, OpenApiVersion::OAS3_1);

assert_json_eq!(
apistos_schema.into_inner(),
json!({
"oneOf": [
{
"title": "Test",
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "Test"
},
"name": {
"type": "string"
}
},
"required": [
"type",
"name"
]
},
{
"title": "Test2",
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "Test2"
},
"surname": {
"type": "string"
}
},
"required": [
"type",
"surname"
]
}
]
})
)
}
}

0 comments on commit 1f28274

Please sign in to comment.