Define array of multiple models in Swagger 2.0 - swagger

This is my first foray into Swagger so please be gentle.
I have the following definitions:
definitions:
Payload:
type: object
properties:
indicators:
type: array
items:
$ref: '#/definitions/Indicator'
Indicator:
type: object
properties:
type:
type: string
computeOn:
type: array
items:
type: string
default:
- close
parameters:
type: object
BBANDS:
properties:
type:
type: string
default: BBANDS
computeOn:
type: array
items:
type: string
default:
- close
parameters:
type: object
properties:
timeperiod:
type: integer
format: int32
default: 5
nbdevup:
type: integer
format: int32
default: 2
nbdevdn:
type: integer
format: int32
default: 2
matype:
type: integer
format: int32
default: 0
DEMA:
properties:
type:
type: string
default: DEMA
computeOn:
type: array
items:
type: string
default:
- close
parameters:
type: object
properties:
timeperiod:
type: integer
format: int32
default: 5
So Payload has a property called indicator which is an array of Indicators. The BBANDS and DEMA are models which are of type Indicator (which I know doesn't translate to Swagger). What I'd like to do is define an array of the actual models with their defaults, in this case BBANDS and DEMA. Something like this:
definitions:
Payload:
type: object
properties:
indicators:
type: array
items:
- '#/definitions/BBANDS'
- '#/definitions/DEMA'
or
definitions:
Payload:
type: object
properties:
indicators:
type: array
items:
- $ref '#/definitions/BBANDS'
- $ref '#/definitions/DEMA'
Neither of which work of course. The reason is while the Indicator model describes an indicator correctly, different indicators can have a different parameter set.
Is there a way to essentially define a list of several models or perhaps map the BBANDS and DEMA models into Indicator?
Edit: Result of using #Helen's first suggestion in the Swagger Editor

Swagger/OpenAPI 2.0 does not support multiple types for items, but there are a couple of ways to describe what you need.
Option 1 - Model Inheritance
As long as you have one field that is common between the models and can be used to distinguish between them, you can use model inheritance:
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#schemaDiscriminator
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#composition-and-inheritance-polymorphism
In your example, this property is type (type="BBANDS" or type="DEMA"). So you can:
Inherit the BBANDS and DEMA models from Indicator by using allOf.
Add discriminator: type to Indicator to indicate that the type property will be used to distinguish between the sub-models.
Define Payload as an array of Indicator. This way it can actually be an array of BBANDS or an array of DEMA.
definitions:
Payload:
type: object
properties:
indicators:
type: array
items:
$ref: '#/definitions/Indicator'
Indicator:
type: object
properties:
type:
type: string
# Limit the possible values if needed
#enum:
# - BBANDS
# - DEMA
computeOn:
type: array
items:
type: string
default:
- close
# The "type" property will be used to distinguish between the sub-models.
# The value of the "type" property MUST be the schema name, that is, "BBANDS" or "DEMA".
# (Or in other words, the sub-model schema names must match possible values of "type".)
discriminator: type
required:
- type
BBANDS:
allOf:
- $ref: '#/definitions/Indicator'
- type: object
properties:
parameters:
type: object
properties:
timeperiod:
type: integer
format: int32
default: 5
nbdevup:
type: integer
format: int32
default: 2
nbdevdn:
type: integer
format: int32
default: 2
matype:
type: integer
format: int32
default: 0
DEMA:
allOf:
- $ref: '#/definitions/Indicator'
- type: object
properties:
parameters:
type: object
properties:
timeperiod:
type: integer
format: int32
default: 5
Option 2 - Single Model
If all parameters are integer, you can have a single model Indicator with parameters defined as a hashmap. But in this case you lose the ability to define the exact parameters for specific indicator types.
definitions:
Indicator:
type: object
properties:
type:
type: string
enum:
- BBANDS
- DEMA
computeOn:
type: array
items:
type: string
default:
- close
parameters:
type: object
properties:
# This is a common parameter in both BBANDS and DEMA
timeperiod:
type: integer
format: int32
default: 5
# This will match additional parameters "nbdevup", "nbdevdn", "matype" in BBANDS
additionalProperties:
type: integer

AFAIK in array type can holds one type, if you want to have multiple types under an array, then need to define another super type and wrap the subtypes in it ( May be using object type ) like bellow. This restriction is because swagger-2.0 doesn't support all the features of json-schema.org, oneOf, anyOf, allOf etc are some of it.
But you can make use the third party extension option available with swagger-2.0. Where you can name a Key with x-, so that means you can include these oneOf like x-oneOf and when parsing the schema you do that using json-schema parser along with swagger schema parser.
One such example is given bellow,
Json-schema
{
"id": "http://some.site.somewhere/entry-schema#",
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "schema for an fstab entry",
"type": "object",
"required": [
"storage"
],
"properties": {
"storage": {
"type": "object",
"oneOf": [
{
"$ref": "#/definitions/diskDevice"
}
]
},
"deviceList": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/definitions/Device"
}
}
},
"definitions": {
"diskDevice": {
"type": "object",
"properties": {
"label": {
"type": "string"
}
},
"required": [
"label"
]
},
"blockDevice": {
"type": "object",
"properties": {
"blockId": {
"type": "number"
}
},
"required": [
"blockId"
]
},
"CharDevice": {
"type": "object",
"properties": {
"charDeviceName": {
"type": "string"
}
},
"required": [
"charDeviceName"
]
},
"Device": {
"type": "object",
"oneOf": [
{
"$ref": "#/definitions/diskDevice"
},
{
"$ref": "#/definitions/blockDevice"
},
{
"$ref": "#/definitions/CharDevice"
}
]
}
}
}
Data or Payload
{
"storage": {"label": "adsf"},
"deviceList": [{"label": "asdf"}, {"blockId": 23}, {"charDeviceName": "asdf"}]
}
Use this site for play around with your sample data - http://www.jsonschemavalidator.net/
Note the deviceList property and how it got constructed. Hope this helps you.

Related

how to define multiple object times in map object in Open api yml

I am newbie to openapi . I need some help in writing open api yml 3.0
for below response format
{
“Details”: {
“detail1”: [
{
"id": “idvalue”1,
“Info”: {
“Testinfo1”: "1.0.0",
“Testinfo2”: "2.0.0"
}
}
],
“Detail2”: [
{
"id": “idvalue2”,
“Info”: {
“Testinfo3”: "1.0.0",
“Testinfo4”: "2.0.0" }
}
],
"Detail3”: [
{
“First name”: “firstName,
“Lastname: “last”Name,
“Address”: “address”,
“Dependents”: []
}
]
},
"links": {
"self": {
"href": “some url”
}
}
}
detail1, detail2, detail3 could be different object types or same object types
and there can be any no of details .
I am struck at below points
how can i represent map open api
how to represent multiple object types with in map.
Check this below YAML snap
DetailsSchemaElement:
type: object
properties:
Details:
type: object
properties:
detail1:
type: array
items:
properties:
id:
type: string
Info:
type: object
properties:
Testinfo1:
type: string
Testinfo2:
type: string
Detail2:
type: array
items:
properties:
id:
type: string
Info:
type: object
properties:
Testinfo4:
type: string
Testinfo3:
type: string
Detail3:
type: array
items:
properties:
First-name:
type: string
Address:
type: string
Dependents:
type: array
items:
type: string
Lastname:
type: string
links:
type: object
properties:
self:
type: object
properties:
href:
type: string

$ref in response example

The response example I would like to put in the yaml file is something like:
{
"name": "Element",
"schema": {
"properties": {
"id": {
"type": "string"
},
"extension": {
"type": "array",
"items": {
"$ref": "#/definitions/Extension"
}
}
}
}
}
And the ymal of this example will be:
responses:
200:
description: "successful operation, return the definition of the resource type in the body"
examples:
application/json:
name: Element
schema:
properties:
id:
type: string
extension:
type: array
items:
$ref: '#/definitions/Extension'
As you can see the last line is "$ref: '#/definitions/Extension'", thus Swagger thinks it is a reference which it can not find anywhere in the ymal file.
Is it possible to escape this to get way from being a reference?
This is a bug in Swagger Editor and UI.
As a workaround, define a schema for your response and use a schema example instead. Schema examples are displayed fine in Swagger Editor 3.6.6 and Swagger UI 3.17.5. You might still see a $ref resolution error in the editor, but at least the example is displayed correctly.
responses:
200:
description: "successful operation, return the definition of the resource type in the body"
schema:
$ref: '#/definitions/MyResponseSchema'
definitions:
MyResponseSchema:
type: object
properties:
name:
type: string
schema:
type: object
properties:
...
example: # <------------
name: Element
schema:
properties:
id:
type: string
extension:
type: array
items:
$ref: '#/definitions/Extension'

Swagger UI: Multiple anonymous objects in array

I am writing Swagger documentation for an API, and one endpoint returns many nested objects and parameters.
There is one returned array, however, which does not return regular parameters. Instead, it returns two anonymous objects that hold the parameters.
"balanceDisplaySettings": [
{
"type": "Balance",
"label": "Current",
"visible": true,
"primary": false
},
{
"type": "AvailableBalance",
"label": "Available",
"visible": true,
"primary": true
}
]
YAML
swagger: '2.0'
schemes:
- https
consumes:
- application/json
produces:
- application/json
paths:
"/Path/":
responses:
'200':
description: OK
schema:
type: object
properties:
balanceDisplaySettings:
type: array
items:
type: object
properties:
type:
type: "Balance"
description: description
label:
type: "Available"
description: description
visible:
type: boolean
description: description
primary:
type: boolean
description: description
type: object
properties:
type:
type: "AvailableBalance"
description: description
label:
type: "Available"
description: description
visible:
type: boolean
description: description
primary:
type: boolean
description: description
Looking at swagger's documentation for Describing Request Body, there is seemingly no way to handle objects without a name.
How do I (Using YAML) document this type of response body in Swagger-UI?
An array of objects is defined like this:
type: array
items:
type: object
properties:
prop1:
type: string
prop2:
type: integer
# etc.
In your example, the response contains an object with the property balanceDisplaySettings, and this property contains an array of objects. This can defined as follows:
paths:
/Path:
get:
responses:
200:
description: OK
schema:
type: object
properties:
balanceDisplaySettings:
type: array
items:
type: object
properties:
type:
type: string
label:
type: string
visible:
type: boolean
primary:
type: boolean
Note that the schema defines the response structure, meaning you don't need to specify the actual values ("Balance", "AvailableBalance", etc.) anywhere. However, if you want to display the example from your post (array with 2 objects) as an example in Swagger UI, you can add it like this:
balanceDisplaySettings:
type: array
items:
type: object
properties:
type:
type: string
label:
type: string
visible:
type: boolean
primary:
type: boolean
example: # <-- example of array of 2 objects
- type: Balance
label: Current
visible: true
primary: false
- type: AvailableBalance
label: Available
visible: true
primary: true
Finally, you may want to split the inline nested schema to make the spec more modular.
paths:
/Path:
get:
responses:
200:
description: OK
schema:
$ref: '#/definitions/MyResponseObject'
# |
definitions: # |
# TODO: better name # |
MyResponseObject: # <--------------+
type: object
properties:
balanceDisplaySettings:
type: array
items:
$ref: '#/definitions/BalanceDisplaySetting'
example: # |
- type: Balance # |
label: Current # |
visible: true # |
primary: false # |
- type: AvailableBalance # |
label: Available # |
visible: true # |
primary: true # |
# |
BalanceDisplaySetting: # <--------+
type: object
properties:
type:
type: string
example: Balance
label:
type: string
example: Current
visible:
type: boolean
boolean:
type: boolean
Another solution is the oneOF parameter.
With it you can use multiple anonymous objects as you want.
Just create some definitions and call them inside items:
"type": "array",
"items": {
"oneOf": [
{ "$ref": "#/components/schemas/Schema1" },
{ "$ref": "#/components/schemas/Schema2" }
]
}
You can read more about here:
https://community.smartbear.com/t5/Swagger-Open-Source-Tools/Can-You-Define-a-Response-Consisting-of-an-Array-With-Two/td-p/186919
Hope it helps

How does swagger works with immutableMap (with different type of values) response?

I have some APIs which returns the following response. How can I use swagger to do the documentation? I know swagger responseContainer supports Map, but the value type of the map seems to have to be the same type. But in my case, the values are in different type: foos is type of List, and the second key "count" corresponds to integer.
Response.ok(ImmutableMap.of("result", foos, "count", foos.size())).build();
The response of the API is something like this:
{
"result": [
{
"f1": "v1",
"f2": "v2"
},
{
"f1": "v3",
"f2": "v4"
}
],
"count": 2
}
Your response can be described like this:
definitions:
MyResponse:
type: object
required:
- result
- count
properties:
result:
type: array
items:
$ref: '#/definitions/Foo'
count:
type: integer
Foo:
type: object
additionalProperties:
type: string

Swagger composition / inheritance

I'm trying to document a REST API using Swagger. A simplified JSON response from our API looks like:
{
"data": {
"type": "person"
"id": "1"
"attributes": {
"name": "Joe"
"age": 32
...
}
"links": {
...
}
}
}
or
{
"data": {
"type": "job"
"id": "22"
"attributes": {
"name": "Manager"
"location": "Somewhere"
...
}
"links": {
...
}
}
}
Their Swagger definitions for a successful GET might look like:
'200':
description: OK.
schema:
type: object
properties:
data:
type: object
properties:
id:
type: string
type:
type: string
attributes:
$ref: '#/definitions/person'
or
'200':
description: OK.
schema:
type: object
properties:
data:
type: object
properties:
id:
type: string
type:
type: string
attributes:
$ref: '#/definitions/job'
There's potentially a lot of repetition like this in our Swagger file. Is it possible to define these responses to share the common parts? i.e. I don't want to type out or copy/paste this part tens of times:
'200':
description: OK.
schema:
type: object
properties:
data:
type: object
properties:
id:
type: string
type:
type: string
I couldn't see how this would work using the discriminator field, or using $ref.
You can use allOf to do composition (in conjunction with discriminator you can do inheritance but it's not really functionnal)
allOf is used with an array of schema or reference, it will create a new definition containing all properties of all definitions in the array.
Given that you want some of your definitions to share id and type properties, it is done this way:
swagger: '2.0'
info:
version: 1.0.0
title: API
paths: {}
definitions:
SharedDefinition:
properties:
id:
type: string
type:
type: string
Person:
allOf:
- $ref: '#/definitions/SharedDefinition'
- properties:
firstname:
type: string
lastname:
type: string
JobSubDefinition:
properties:
name:
type: string
Job:
allOf:
- $ref: '#/definitions/SharedDefinition'
- $ref: '#/definitions/JobSubDefinition'
In this example:
Person = SharedDefinition + inline definition
Job = SharedDefinition + JobSubDefinition
More about this in
Writing OpenAPI (Swagger) Specification Tutorial – Part 4 – Advanced Data Modeling (disclosure: I wrote this tutorial)
OpenAPI Specification#models-with-composition

Resources