fix(schema): remove AddNullable from draft2020_12 settings (#664)
* fix(schema): remove AddNullable from draft2020_12 settings
The `nullable` keyword is an OpenAPI 3.0 extension, not part of
JSON Schema 2020-12. Using AddNullable with draft2020_12 settings
causes validation failures with strict JSON Schema validators.
JSON Schema 2020-12 represents nullable types using:
- {"type": ["string", "null"]} (type array with null)
- {"anyOf": [{"type": "string"}, {"type": "null"}]}
Fixes #663
* test(schema): update complex schema nullable expectation
* test(schema): align macro optional-field expectations with draft2020
This commit is contained in:
parent
3df4c5bf5f
commit
92b1459647
3 changed files with 24 additions and 21 deletions
|
|
@ -23,8 +23,10 @@ pub fn schema_for_type<T: JsonSchema + std::any::Any>() -> Arc<JsonObject> {
|
|||
} else {
|
||||
// explicitly to align json schema version to official specifications.
|
||||
// refer to https://github.com/modelcontextprotocol/modelcontextprotocol/pull/655 for details.
|
||||
let mut settings = SchemaSettings::draft2020_12();
|
||||
settings.transforms = vec![Box::new(schemars::transform::AddNullable::default())];
|
||||
let settings = SchemaSettings::draft2020_12();
|
||||
// Note: AddNullable is intentionally NOT used here because the `nullable` keyword
|
||||
// is an OpenAPI 3.0 extension, not part of JSON Schema 2020-12. Using it would
|
||||
// cause validation failures with strict JSON Schema validators.
|
||||
let generator = settings.into_generator();
|
||||
let schema = generator.into_root_schema_for::<T>();
|
||||
let object = serde_json::to_value(schema).expect("failed to serialize schema");
|
||||
|
|
|
|||
|
|
@ -80,8 +80,10 @@ fn expected_schema() -> serde_json::Value {
|
|||
"type": "array"
|
||||
},
|
||||
"system": {
|
||||
"nullable": true,
|
||||
"type": "string"
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ fn test_optional_field_schema_generation_via_macro() {
|
|||
);
|
||||
|
||||
// Verify the schema generated for the aggregated OptionalFieldTestSchema
|
||||
// by the macro infrastructure (which should now use OpenAPI 3 settings)
|
||||
// by the macro infrastructure using JSON Schema 2020-12 settings.
|
||||
let input_schema_map = &*tool_attr.input_schema; // Dereference Arc<JsonObject>
|
||||
|
||||
// Check the schema for the 'description' property within the input schema
|
||||
|
|
@ -253,18 +253,21 @@ fn test_optional_field_schema_generation_via_macro() {
|
|||
.as_object()
|
||||
.unwrap();
|
||||
|
||||
// Assert that the format is now `type: "string", nullable: true`
|
||||
// Assert nullable Option<T> is represented in JSON Schema 2020-12 form.
|
||||
let type_value = description_schema
|
||||
.get("type")
|
||||
.expect("Schema for Option<String> should include a type field");
|
||||
let type_array = type_value
|
||||
.as_array()
|
||||
.expect("Schema for Option<String> should use a type array [T, null]");
|
||||
assert_eq!(
|
||||
description_schema.get("type").map(|v| v.as_str().unwrap()),
|
||||
Some("string"),
|
||||
"Schema for Option<String> generated by macro should be type: \"string\""
|
||||
type_array,
|
||||
&vec![serde_json::json!("string"), serde_json::json!("null")],
|
||||
"Schema for Option<String> should be type: [\"string\", \"null\"]"
|
||||
);
|
||||
assert_eq!(
|
||||
description_schema
|
||||
.get("nullable")
|
||||
.map(|v| v.as_bool().unwrap()),
|
||||
Some(true),
|
||||
"Schema for Option<String> generated by macro should have nullable: true"
|
||||
assert!(
|
||||
description_schema.get("nullable").is_none(),
|
||||
"Schema for Option<String> should not use OpenAPI nullable in JSON Schema 2020-12"
|
||||
);
|
||||
// We still check the description is correct
|
||||
assert_eq!(
|
||||
|
|
@ -274,12 +277,8 @@ fn test_optional_field_schema_generation_via_macro() {
|
|||
Some("An optional description field")
|
||||
);
|
||||
|
||||
// Ensure the old 'type: [T, null]' format is NOT used
|
||||
let type_value = description_schema.get("type").unwrap();
|
||||
assert!(
|
||||
!type_value.is_array(),
|
||||
"Schema type should not be an array [T, null]"
|
||||
);
|
||||
// Ensure no OpenAPI-only nullable extension was emitted.
|
||||
assert!(description_schema.get("nullable").is_none());
|
||||
}
|
||||
|
||||
// Define a dummy client handler
|
||||
|
|
|
|||
Loading…
Reference in a new issue