This document describes how to extend Swagger data models to allow the types of fields to vary.
Given that Swagger models need to map cleanly to a statically typed object model, a subclassing approach seems like it would be a good fit.
Inheritance allows a model (the derived type) to inherit all of the properties of another (the base type). This allows for a more compact representation of models, since common sets of fields may be extracted into a base type. This also allows the Swagger data model to match more closely to what an object model might look like.
Inheritance is transitive, meaning that if the base type inherits from another model, the derived type inherits those properties, too.
To declare an inheritance relationship between two models, a field
extends
is added to the derived type's model definition, which gives
the id of the base type.
Only single inheritance is supported; meaning at most one extends
field may be declared on a given model.
The derived type MUST NOT redefine any properties defined in any of its base types.
The base type named in an extends
field SHOULD be defined within the
same API declaration.
The extends
relationship between models MUST NOT be cyclic.
This example defines four models, with a fairly simple inheritance relationship between them.
+--- Foo <--- Bar
|
Base <---+
|
+--- Bam
Base
is the base type, with a single property baseProp
. Foo
derives from Base
, so it inherits the property baseProp
, in
addition to defining its own property fooProp
. Bar
derives from Foo
,
and inherits both baseProp
and fooProp
. Finally, Bam
also
derives from Base
, so it inherits baseProp
.
"models": {
"Base": {
"id": "Base",
"properties": { "baseProp": { "type": "string" } }
},
"Foo": {
"id": "Foo",
"extends": "Base",
"properties": { "fooProp": { "type": "string"} }
},
"Bar": {
"id": "Bar",
"extends": "Foo",
"properties": { "barProp": { "type": "string"} }
},
"Bam": {
"id": "Bam",
"extends": "Base",
"properties": { "bamProp": { "type": "string"} }
}
}
Here are some example objects that would conform to this model:
Base - { "baseProp": "base" }
Foo - { "baseProp": "base", "fooProp": "foo" }
Bar - { "baseProp": "base", "fooProp": "foo", "barProp": "bar" }
Bam - { "baseProp": "base", "bamProp": "bam" }
In the above examples, there is no practical way for the client to
determine the specific type of a received object. The ability to do so
is very useful in being able to treat types polymorphically. If such a
polymorphic base type is declared as the responseClass
of an
operation, the consumer can determine the type of object they are
receiving.
To declare that a type may be treated polymorphically, a field
discriminator
is added to the type's model definition, which gives
the id of the property to be used to identify the type of an object.
The named field MUST be of type string
, and MUST be required
. The
allowableValues
for the property will be implicitly be the list of
ids of all derived subtypes.
At most one discriminator
field may be declared on a given model.
Since the field is inherited by subtypes, they MUST NOT declare their
own discriminator.
Subtypes are defined using the extends
field, as described in the
Inheritance section above.
This example defines two classes to simply demonstrate the use of the discriminator field.
Animal <--- Cat
Animal
is the base type, with two properties: id
and dtype
, with
dtype
identified as the discriminator. Cat
extends Animal
, and
adds a name
property.
"models": {
"Animal": {
"id": "Animal",
"discriminator": "dtype",
"properties": {
"id": { "type": "long", },
"dtype": { "type": "string", "required": true }
}
},
"Cat": {
"id": "Cat",
"extends": Animal"
"properties": {
"name": { "type": "string" }
}
}
}
Since Animal
declares a discriminator field, it may be treated
polymorphically. If an operation's responseClass
is Animal
, it may
safely return Animal
s or Cat
s.
Some valid objects that conforms to the Animal
model:
{ "dtype": "Animal", "id": 8675309 }
{ "dtype": "Cat", "id": 3141593, "name": "Fluffy" }
Cat
should extendAnimal
, since that's the type name in the model. Other than that, it looks great.