Schema Objects in particular provide the models for request and response message payloads:
- They can be defined in-context, as the schema value of a body parameter or response; or
- They can appear in the definitions section and included by reference.
Swagger's Schema Object provides limited support for JSON Schema's additionalProperties keyword. Used within an object schema, additionalProperties allows objects conforming to the schema to include properties that are not explicitly named in the properties section of the schema.
However, Swagger's core libraries deviate from the specification in subtle ways that can cause unexpected behavior. RepreZen API Studio mitigates these issues and provides workarounds wherever practical. But the core libraries are used throughout the Swagger tools ecosystem, so some limitations remain.
Boolean true and false Values Not Supported
In JSON Schema, additionalProperties has a default value of empty schema, which is equivalent to additionalProperties: true. This means that, unless your JSON Schema says otherwise, unspecified properties can appear in an object, without restriction. And as long as the object meets the other requirements specified in the schema, the object still conforms.
JSON Schema allows you to specify an additionalProperties value of true, which just makes the default behavior explicit, or false, which means that only explicitly specified properties are allowed.
While the Swagger 2.0 specification doesn't say anything to contradict this, the implementation libraries ignore boolean true and false values. They have no effect on documentation and generated code produced from your Swagger specification. Some comments suggest that the default behavior in Swagger should be to disallow additional properties, but this is not in the Swagger 2.0 spec.
Limitations on Schemas with Both properties and additionalProperties
Aside from boolean true and false values, JSON Schema also allows additionalProperties to specify a schema as its value. In this case, additional properties are allowed, as long as their values conform to the specified schema. This "schema form" is the only form supported by Swagger.
JSON Schema allows schemas that combine explicitly defined properties with additionalProperties. We'll call this a combination schema. However, in certain contexts, Swagger doesn't support combination schemas. The schema can use either additionalProperties or properties alone. But if both keywords appear, one of the two will be ignored. The resulting schema will behave as if only additionalProperties or properties were defined.
The limitations are specific to the context in which the Schema is defined. Combination schemas work properly in the following contexts:
- as the value of a schema keyword in a body parameter
- as the value of a top-level schema in the definitions object
- within allOf , as an element of a schema array:
Combination schemas are not supported in these other contexts:
- as the value of a schema keyword in a response
- as a property schema, appearing as the value of a named property in a properties map
- as an array item schema, appearing as the value of the value of the items keyword
- as the value of an additionalProperties schema
Schemas in these unsupported contexts will ignore properties or additionalProperties if they are both defined in the schema.
Workaround: Define and Reference Combination Schemas
You can work around this limitation by extracting the combination schema to its own top-level schema, declared in the definitions object. Once defined, you can reference the combination schema wherever you need it, even in contexts that don't support combination schemas declared in-line.
In this example, Membership no longer declares the combination schema in-line. Instead, the combination schema is extracted as MemberProfile, and included by reference. The combination schema is now defined in a supported context, so it is processed correctly.
The cause of these issues is deeply rooted in the design of the Swagger-Models library. As background info for developers who may be interested:
- The full-featured schema representation makes use of the Model class and its subclasses in the swagger-models module of the swagger-core project.
- ModelImpl is used for object schemas and also primitive type schemas
- ArrayModel is used for array schemas
- ComposedModel is used for allOf schemas and has no provision for directly contained properties
- The restricted schema representation makes use of Property and its subclasses, also in swagger-models
- ObjectProperty represents object schemas with regular, explicitly defined properties, and has no provision for additionalProperties.
- MappingProperty represents object schemas with additionalProperties and discards explicitly defined properties.
- ArrayProperty is used for array properties
- Many subclasses exist for representing the various primitive types
- The code that notices an allOf and switches to ComposedModel (thereby silently discarding static properties) is in the swagger-core module of the swagger-core project, in util/ModelDeserializer.java
- Anywhere in the model where a schema should be permitted but you see a Java field of type Property constitutes a restricted schema context. E.g. in swagger-models in Response.java you see private Property schema, which means response schemas are restricted. In contrast, in parameters/BodyParameter.java you see Model schema which means body params are not a restricted context.