OpenAPI 3.0.0, Swagger online editor.
I composed subschemas via the allOf discriminator and set the example field for a resulting schema. Swagger UI, however, didn't provide the example as-is.
The schema contained an array originating from the subschema. The array inherited example items from the subschema and extended the list with the examples from the schema.
Example
Let's say we have two schemas:
Cats:
type: object
properties:
cats:
type: array
items:
type: object
properties:
fluffiness:
type: integer
names:
type: string
example:
cats:
- fluffiness: 9
names: "Felix"
- fluffiness: 10
names: "Neko"
FluffiestCats:
allOf:
- $ref: '#/components/schemas/Cats'
- type: object
properties:
date:
type: string
format: "date"
example:
cats:
- fluffiness: 10
names: "Luna"
- fluffiness: 10
names: "Meowie"
date: "17-01-2021"
Responding to some request, the API retrieves the fluffiest cats, referencing #/components/schemas/FluffiestCats/. Swagger UI generates the following response example.
{
"cats": [
{
"fluffiness": 9,
"names": "Felix"
},
{
"fluffiness": 10,
"names": "Neko"
},
{
"fluffiness": 10,
"names": "Luna"
},
{
"fluffiness": 10,
"names": "Meowie"
}
],
"date": "17-01-2021"
}
Swagger UI takes two examples from the subschema example items. The provided example doesn't override the subschema example.
Does this behaviour contradict the specification? According to the description, it seems the Schema Object's example field doesn't imply override, in contrast to the Parameter Object's example field.
How can I override the subschema example? Or do I have to recreate the schema without using the allOf?
References
How to reference array item examples in OpenAPI 3?
OpenAPI 3.0.0 specification
It was an issue with Swagger UI.
Fixed in Swagger UI 4.5.0 and Swagger Editor 4.0.7.
Related
I've been struggling with an issue in an openapi 3.0.1 spec json document I've been working on.
The issue I'm seeing in the online swagger editor (editor.swagger.io) is very strange where the Request body Example Value section of a POST does not show the "layers", which is an array defined within my MixBase schema component, based on the MixLayer schema component. The MixLayer schema component has an array of MixLayerComponent schema components.
However, if I include a $ref to the MixBase schema in the responses section, all the elements are shown correctly.
Request body Example Value section that is missing the 'layers':
{
"mixId": "4f8b533f-7449-4056-92ff-11b1de94d656",
"mixDescription": "SES5M",
"mixScaleName": "MyScale",
"mixRoom": "MixingRoomABC",
"mixProgramId": "ABC-123-ProgramId",
"mixDateTime": "2018-06-07T12:51:25.077Z",
"mixState": "Paused",
"mixNumber": "131",
"mixedByUserName": "john.smith#example.com",
"mixedByFirstName": "John",
"mixedByLastName": "Smith"
}
Responses Example Value section returning the correct list of elements including 'layers':
{
"mixId": "4f8b533f-7449-4056-92ff-11b1de94d656",
"mixDescription": "SES5M",
"mixScaleName": "MyScale",
"mixRoom": "MixingRoomABC",
"mixProgramId": "ABC-123-ProgramId",
"mixDateTime": "2018-06-07T12:51:25.077Z",
"mixState": "Paused",
"mixNumber": "131",
"mixedByUserName": "john.smith#example.com",
"mixedByFirstName": "John",
"mixedByLastName": "Smith",
"layers": [ -- this represents the MixLayer component
{
"unitOfMeasure": "g",
"Components": [ -- this represents the MixLayerComponent correctly
{
"code": "800C",
"description": "800C",
"poured": 204.5,
"density": 1.041
}
]
}
]
}
My requestBody section is defined as: (doesn't show 'layers')
requestBody:
required: true
description: Paint mix information to create
content:
application/json:
schema:
$ref: '#/components/schemas/MixBase'
My responses section is defined as: (and this displays correctly in the Response examples section)
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/MixBase'
Here is the definition of the 'layers' within the MixBase schema component (which is the last element in the MixBase definition which is why additionalProperties is set to false): (The formatting might not be correct in stack overflow but the swagger editor doesn't complain so I don't believe the issue is linked to formatting)
layers:
description: Layer related information for components of the mix
type: array
items:
$ref: '#/components/schemas/MixLayer'
readOnly: true
additionalProperties: false
Here is the definition of the MixLayer:
MixLayer:
required:
- Components
type: object
properties:
unitOfMeasure:
description: Unit of volume for the components of the layer
maxLength: 10
type: string
nullable: true
example: g
Components:
description: The components that make up the layer in the mix
type: array
items:
$ref: '#/components/schemas/MixLayerComponent'
readOnly: true
additionalProperties: false
Here is the definition of the MixLayerComponent:
MixLayerComponent:
required:
- code
- density
- poured
type: object
properties:
code:
description: The code associated with the mix component of the layer
maxLength: 25
minLength: 1
type: string
example: 800C
description:
description: The description of the mix component of the layer
maxLength: 120
type: string
nullable: true
example: 800C
poured:
description: >-
The quantity, expressed in the unit of measurement, consumed for the
mix component
type: number
format: double
example: 204.5
density:
description: The density associated with the mix component of the layer
type: number
format: double
example: 1.041
additionalProperties: false
I thought that the "Components" element in the MixLayer component schema might be a reserved keyword in openapi so I changed the references to something else and it still has the same issue.
I thought this issue might be with the online swagger editor (editor.swagger.io) but the same thing occurs in Postman. I also tried browsers Chrome, Edge, and Firefox and they all
have the same issue. I have also tried an XML content type in addition to the JSON I would like to use but still the same issue.
I don't access to post my openapi.json file on stack overflow but I hope this provides enough information.
Any insights anyone has for me to continue a line of investigation would be greatly appreciated.
Thank you for your time in advance,
Dave
layers is defined as a read-only property (readOnly: true) - that's why it doesn't appear in the request body example.
From my Java backend I'm consuming another backend which I don't manage and it's API definition is not available. I'm creating the OpenAPI definition of it's services and using Swagger Codegen to generate the client.
There is an endpoint which returns a complex object:
{
"total": 151,
"version": 4,
"dynamicItem1": [
"codeDynamicItem1",
293,
63700,
19,
"nameDynamicItem1",
"",
"",
"",
0,
-64
],
"dynamicItem2": [
"codeDynamicItem2",
237,
40000,
478,
"nameDynamicItem2",
"string1",
"string2",
"string3",
0,
0
]
}
In that object the total and version are always there but on the same level there are hundreds of those dynamic items. The key is predictable in the example above but in reality is a sequence of letter and numbers, something like "245df921". The dynamic items are always arrays with the same number of items and in the same expected positions.
To parse that object I'm using additionalProperties beacuse I read that it's the right way to parse hashmaps, but seems like I'm not applying it correctly.
Currently my OpenAPI representation looks like this:
openapi: 3.0.2
info:
version: 1.0.0
title: title
description: description
paths:
/complexObject:
get:
responses:
'200':
description: "OK"
content:
application/json:
schema:
$ref: '#/components/schemas/Object'
components:
schemas:
Object:
type: object
properties:
total:
type: number
example: 151
version:
type: number
example: 4
additionalProperties:
type: array
items:
type: string
nullable: true
Using that implementation the total and version are returned properly but in the response object there is an additionalProperties attribute with null value.
What am I missing?
additionalProperties needs to be on the same level as properties.
Also, since those dynamic array are multi-type (string / integer) you need oneOf to define possible item types.
components:
schemas:
Object:
type: object
properties:
total:
type: number
example: 151
version:
type: number
example: 4
additionalProperties: # <-----
type: array
items:
oneOf: # <-----
- type: string
nullable: true
- type: integer
I trying to map the following JSON to an OpenAPI 2.0 (Swagger 2.0) YAML definition, and I am not sure how to set mixed array types into my schema:
{
"obj1": [
"string data",
1
]
}
Now, my OpenAPI definition has:
schema:
object1:
type: array
items:
type: string
but this doesn't allow integers inside the array.
Is there a way to define a mixed type array?
The answer depends on which version of the OpenAPI Specification you use.
OpenAPI 3.1
type can be a list of types, so you can write your schema as:
# openapi: 3.1.0
obj1:
type: array
items:
type: [string, integer]
# or if nulls are allowed:
# type: [string, integer, 'null']
OpenAPI 3.0.x
Mixed types are supported in OpenAPI 3.0 using oneOf / anyOf and optionally nullable: true to also allow nulls.
# openapi: 3.0.1
obj1:
type: array
items:
oneOf:
- type: string
nullable: true # If nulls are allowed
- type: integer
OpenAPI 2.0
OpenAPI 2.0 (Swagger 2.0) does not really support mixed-type array and parameters. The most you can do is to use a typeless schema {} for items, which means the items can be anything (except null) – numbers, objects, strings, etc. You cannot specify the exact types for items, but you can add an example of an array with different item types.
# swagger: '2.0'
obj1:
type: array
items: {} # <--- means "any type" (except null)
example:
- string data
- 1
Note: Typeless schema {} can only be used in body parameters and response schemas. Path, header and form parameters require a primitive type for array items.
I trying to map the following JSON to an OpenAPI 2.0 (Swagger 2.0) YAML definition, and I am not sure how to set mixed array types into my schema:
{
"obj1": [
"string data",
1
]
}
Now, my OpenAPI definition has:
schema:
object1:
type: array
items:
type: string
but this doesn't allow integers inside the array.
Is there a way to define a mixed type array?
The answer depends on which version of the OpenAPI Specification you use.
OpenAPI 3.1
type can be a list of types, so you can write your schema as:
# openapi: 3.1.0
obj1:
type: array
items:
type: [string, integer]
# or if nulls are allowed:
# type: [string, integer, 'null']
OpenAPI 3.0.x
Mixed types are supported in OpenAPI 3.0 using oneOf / anyOf and optionally nullable: true to also allow nulls.
# openapi: 3.0.1
obj1:
type: array
items:
oneOf:
- type: string
nullable: true # If nulls are allowed
- type: integer
OpenAPI 2.0
OpenAPI 2.0 (Swagger 2.0) does not really support mixed-type array and parameters. The most you can do is to use a typeless schema {} for items, which means the items can be anything (except null) – numbers, objects, strings, etc. You cannot specify the exact types for items, but you can add an example of an array with different item types.
# swagger: '2.0'
obj1:
type: array
items: {} # <--- means "any type" (except null)
example:
- string data
- 1
Note: Typeless schema {} can only be used in body parameters and response schemas. Path, header and form parameters require a primitive type for array items.
How to specify a property as null or a reference? discusses how to specify a property as null or a reference using jsonschema.
I'm looking to do the same thing with swagger.
To recap the answer to the above, with jsonschema, one could do this:
{
"definitions": {
"Foo": {
# some complex object
}
},
"type": "object",
"properties": {
"foo": {
"oneOf": [
{"$ref": "#/definitions/Foo"},
{"type": "null"}
]
}
}
}
The key point to the answer was the use of oneOf.
The key points to my question:
I have a complex object which I want to keep DRY so I put it in a
definitions section for reuse throughout my swagger spec: values of other properties; response objects, etc.
In various places in my spec a
property may be a reference to such an object OR be null.
How do I specify this with Swagger which doesn't support oneOf or
anyOf?
Note: some swagger implementations use x-nullable (or some-such) to specify a property value can be null, however, $ref replaces the object with what it references, so it would appear any use of x-nullable is ignored.
OpenAPI 3.1
Define the property as anyOf of the $ref and type: 'null'.
YAML version:
foo:
anyOf:
- type: 'null' # Note the quotes around 'null'
- $ref: '#/components/schemas/Foo'
JSON version:
"foo": {
"anyOf": [
{ "type": "null" },
{ "$ref": "#/components/schemas/Foo" }
]
}
Why use anyOf and not oneOf? oneOf will fail validation if the referenced schema itself allows nulls, whereas anyOf will work.
OpenAPI 3.0
YAML version:
foo:
nullable: true
allOf:
- $ref: '#/components/schemas/Foo'
JSON version:
"foo": {
"nullable": true,
"allOf": [
{ "$ref": "#/components/schemas/Foo" }
]
}
In OAS 3.0, wrapping $ref into allOf is needed to combine the $ref with other keywords - because $ref overwrites any sibling keywords. This is further discussed in the OpenAPI Specification repository: Reference objects don't combine well with “nullable”
Not easy to do that. Even almost impossible. Your options :
Wait
There is a very long discussion about this point, maybe one day it will be done...
Use vendors extensions
You can use vendors extensions like x-oneOf and x-anyOf. I have already taken this hard way: You must to upgrade all used 'swagger tools' to take into account these vendors extensions.
In my case, we needed 'only' to :
Develops our own Jax-RS parser with customized annotations in order to extract swagger API file from sources
Extends swagger-codegen to take into account these extensions to generate java code for our clients
Develops our own swagger-ui: to facilitate this work, we added a preprocessing step to convert our swagger schema with our extensions to a valid json schema. It's easier to find a module to represent json schemas than swagger schemas in javascript. By cons we gave up the idea to test the API with the 'try it' button.
It was a year ago, maybe now ...
Refactor your APIs
Many projects don't need anyOf and oneOf, why not us ?
For OpenAPI 3.0 for some reason using nullable: true followed by allOf didn't work for the OpenAPI interpreter I'm using. As a workaround I ended up defining a must-be-null ref called null_type that I can use in an anyOf construct.
Like so:
allOf:
- anyOf:
- $ref: "#/components/schemas/null_type"
- $ref: "#/components/schemas/your_ref"
- description: "optionally add other properties here..."
where:
schemas:
null_type:
title: "OpenAPI 3.0 null-type ref"
description: "for adding nullability to a ref"
enum: [null]
your_ref:
...