diff --git a/schemars/tests/expected/struct-normal-additional-properties.json b/schemars/tests/expected/struct-normal-additional-properties.json new file mode 100644 index 0000000..7788e4a --- /dev/null +++ b/schemars/tests/expected/struct-normal-additional-properties.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Struct", + "type": "object", + "additionalProperties": false, + "required": [ + "bar", + "foo" + ], + "properties": { + "bar": { + "type": "boolean" + }, + "baz": { + "type": [ + "string", + "null" + ] + }, + "foo": { + "type": "integer", + "format": "int32" + } + } +} diff --git a/schemars/tests/struct_additional_properties.rs b/schemars/tests/struct_additional_properties.rs new file mode 100644 index 0000000..294e465 --- /dev/null +++ b/schemars/tests/struct_additional_properties.rs @@ -0,0 +1,16 @@ +mod util; +use schemars::JsonSchema; +use util::*; + +#[derive(Debug, JsonSchema)] +#[serde(deny_unknown_fields)] +pub struct Struct { + foo: i32, + bar: bool, + baz: Option, +} + +#[test] +fn struct_normal_additional_properties() -> TestResult { + test_default_generated_schema::("struct-normal-additional-properties") +} diff --git a/schemars_derive/src/attr/schemars_to_serde.rs b/schemars_derive/src/attr/schemars_to_serde.rs index 22042d2..20b7b10 100644 --- a/schemars_derive/src/attr/schemars_to_serde.rs +++ b/schemars_derive/src/attr/schemars_to_serde.rs @@ -8,8 +8,7 @@ use syn::{Attribute, Data, Field, Meta, NestedMeta, Variant}; static SERDE_KEYWORDS: &[&str] = &[ "rename", "rename_all", - // TODO: for structs with `deny_unknown_fields`, set schema's `additionalProperties` to false. - // "deny_unknown_fields", + "deny_unknown_fields", "tag", "content", "untagged", diff --git a/schemars_derive/src/schema_exprs.rs b/schemars_derive/src/schema_exprs.rs index ba557fb..ec1a5a5 100644 --- a/schemars_derive/src/schema_exprs.rs +++ b/schemars_derive/src/schema_exprs.rs @@ -362,12 +362,23 @@ fn expr_for_struct(fields: &[Field], cattrs: Option<&serde_attr::Container>) -> }) .collect(); + let deny_unknown_fields = cattrs + .map_or(false, |attrs| attrs.deny_unknown_fields()); + quote! { { #(#type_defs)* #set_container_default let mut schema_object = schemars::schema::SchemaObject { instance_type: Some(schemars::schema::InstanceType::Object.into()), + object: Some(Box::new(schemars::schema::ObjectValidation { + additional_properties: if #deny_unknown_fields { + Some(Box::new(false.into())) + } else { + None + }, + ..Default::default() + })), ..Default::default() }; #(#properties)*