How to extend a defined response in OpenAPI? - swagger

I want to extend the "200SuccessDefault" response with a schema or example.
paths:
/home:
...
responses:
200:
$ref: '#/components/responses/200SuccessDefault'
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/PieChartElement'
examples:
PieChart:
$ref: '#/components/examples/PieChart_1'
This approach runs into an error, the schema and examples fields are ignored:
Sibling values alongside $refs are ignored. To add properties to a $ref, wrap the $ref into allOf, or move the extra properties into the referenced definition (if applicable).
I tried allOf:
paths:
/home:
responses:
200:
allOf:
- $ref: '#/components/responses/200SuccessDefault'
- content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/PieChartElement'
examples:
PieChart:
$ref: '#/components/examples/PieChart_1'
This approach runs into the error:
should NOT have additional properties additionalProperty: allOf
should have required property 'description' missingProperty: description

You cannot extend a referenced response object. But, you can use a shared schema object and extend it utilizing allOf within schema.
Inside allOf you can put:
your $ref
a new type extending your default response
If you want to give an example of an entire extended response (JSON), just put it into "application/json".
An example of OpenAPI would be:
"202":
description: Extended response sample
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/application"
- type: object
properties:
anotherProperty:
type: string
maxLength: 200
example: "Property example"
example: {id: 1234, anotherProperty: "Hello"}

Related

Which is the correct allOf syntax for OpenAPI 3 schema inheritance?

Which syntax is correct - the first one, the second one, or both?
components:
schemas:
FileContent:
allOf:
- $ref: '#/components/schemas/FileInfo'
- type: object
properties:
storageMethod:
$ref: '#/components/schemas/StorageMethod'
contentRange:
type: string
nullable: true
# ... other properties ...
additionalProperties: false
components:
schemas:
FileContent:
type: object
allOf:
- $ref: '#/components/schemas/FileInfo'
properties:
storageMethod:
$ref: '#/components/schemas/StorageMethod'
contentRange:
type: string
nullable: true
# ... other properties ...
additionalProperties: false
In terms of allOf syntax, both versions are correct and technically equivalent:
allOf:
- $ref: '#/components/schemas/Foo'
- properties:
# other properties
# ...
allOf:
- $ref: '#/components/schemas/Foo'
properties:
# other properties
# ...
In OpenAPI 3.1 (which uses JSON Schema 2020-12 by default), there's even no need for allOf if you only have one $ref because $ref now allows sibling keywords. (But you still need allOf to "combine" multiple $refs.)
# openapi: 3.1.0
$ref: '#/components/schemas/Foo'
properties:
# other properties
# ...
The error in your examples is elsewhere - it's the presence of additionalProperties: false. This keyword is problematic because it only knows about its immediate sibling properties and has no visibility into allOf/oneOf/anyOf subschemas or "inherited" schemas. For your examples, this means that properties defined in the FileInfo schema won't actually be allowed in the composed schema.
Here are some more examples to illustrate that additionalProperties: false doesn't work the way one would expect:
allOf:
- $ref: '#/components/schemas/Foo'
- $ref: '#/components/schemas/Bar'
additionalProperties: false
# Expected: Only the properties defined in Foo and Bar are allowed
# Actual: No properties are allowed
allOf:
- $ref: '#/components/schemas/Foo'
- properties:
prop:
type: string
additionalProperties: false
# Expected: The allowed properties are `prop` and those defined in the Foo schema
# Actual: Only the `prop` property is allowed
allOf:
- $ref: '#/components/schemas/Foo'
properties:
prop:
type: string
additionalProperties: false
# Expected: The allowed properties are `prop` and those defined in the Foo schema
# Actual: Only the `prop` property is allowed
Foo:
type: object
properties:
foo:
type: string
additionalProperties: false
Bar:
allOf:
- $ref: '#/components/schemas/Foo'
- properties:
prop:
type: string
# Expected: The Bar schema allows properties from Foo + the `prop` property
# Actual: The Bar schema allows only properties from Foo
This is solved in OpenAPI 3.1 / JSON Schema 2019-09+ by the new unevaluatedProperties: false keyword. So the following will work the way you expect:
# openapi: 3.1.0
$ref: '#/components/schemas/Foo'
properties:
prop:
type: string
unevaluatedProperties: false
I think the second one: for a long time, schema keywords adjacent to $ref were ignored in json schemas. Later they changed it in the spec (AFAIK), but I'm not sure if all the tooling & implementations caught up with that.
Yet my personal preference is putting both the parent schema and child schema props under an allOf, like
schemas:
FileContent:
allOf:
- $ref: '#/components/schemas/FileInfo'
- type: object
properties:
storageMethod:
$ref: '#/components/schemas/StorageMethod'
contentRange:
type: string
nullable: true
totalLength:
type: integer
format: int64

How can i get different request body schemas, depending on selected Media type in NestJs/Swagger?

I want to implement something like that:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/FaceEnrollmentRequest'
multipart/form-data:
schema:
$ref: '#/components/schemas/FaceEnrollmentRequestMultipart'

How to define an OpenAPI ordered array of different objects?

I am trying to define my API using OpenAPI version 3.0. I am trying to generate a YAML file which has four maps, and each map contains a different information. How can I create a YAML file to achieve that goal? I know that my components are not right because of which I am not getting the right result.
Request body should be like this:
[
UserInformation{FirstName, LastName},
AddressInformation{Phone, Address},
ContactInformation{Email, Phone}
]
openapi: 3.0.0
info:
version: 1.0.0
title: 'INPUT-FORM-API'
paths:
/api/v1/test/healthcheck:
get:
summary: Health check for the test api services. Used Internally
operationId: Externalhealthcheck
description: healthcheck for the test services status.
responses:
'200':
description: This status is always returned when service is Ok.
content:
application/json:
schema:
$ref: '#/components/schemas/HealthcheckObject'
/api/v1/test/newformentry:
post:
summary: End Point to insert data into the new table.
operationId: NewFormEntry
description: EndPoint to insert data for new form.
requestBody:
content:
application/json:
schema:
items:
$ref: '#/components/schemas/NewFormEntry'
responses:
'200':
description: This status is always returned when service is Ok.
content:
application/json:
schema:
$ref: '#/components/schemas/HealthcheckObject'
components:
schemas:
NewFormEntry:
$ref: '#/components/schemas/UserInformation'
$ref: '#/components/schemas/AddressInformation'
$ref: '#/components/schemas/ContactInformation'
$ref: '#/components/schemas/MessageFromBene'
UserInformation:
required:
- FirstName
- LastName
properties:
FirstName:
type: string
LastName:
type: string
AddressInformation:
required:
- StreetAddress
- City
- State
- ZipCode
properties:
StreetAddress:
type: string
StreetAddress2:
type: string
City:
type: string
State:
type: string
ZipCode:
type: integer
format: int64
ContactInformation:
required:
- PhoneNumber
- Email
properties:
PhoneNumber:
type: integer
format: int64
maximum: 9
Email:
type: string
HomePhone:
type: integer
format: int64
maximum: 9
Cell:
type: integer
format: int64
maximum: 9
WorkPhone:
type: integer
format: int64
maximum: 9
MessageFromBene:
required:
- Message
properties:
PhoneNumber:
type: integer
format: int64
maximum: 9
Message:
type: string
HealthcheckObject:
required:
- Status
- ErrorMessage
properties:
Status:
type: string
ErrorMessage:
type: string
So the NewFormEntry schema must be an array containing 3 objects, where the 1st object must be UserInformation, the second object must be AddressInformation, and the 3rd object mube be ContactInformation. This is like a tuple, i.e. an ordered sequence of elements where each element has a specfic type. Tuple definitions are slightly different in different OpenAPI versions.
OpenAPI 3.1
If or when you migrate to OAS 3.1, such an array can be defined using prefixItems. This keyword specifies the schema for each element position (in other words, it specifies the order of elements in the array):
components:
schemas:
NewFormEntry:
type: array
prefixItems:
- $ref: '#/components/schemas/UserInformation' # type of the 1st element
- $ref: '#/components/schemas/AddressInformation' # type of the 2nd element
- $ref: '#/components/schemas/ContactInformation' # type of the 3rd element
minItems: 3
maxItems: 3
additionalItems: false # can be omitted if `maxItems: 3` is specified
OpenAPI 3.0
In OAS 3.0, you can define the array length (i.e. 3 items) and the possible types of array items (i.e. each item can be either A, B, or C), but there's no way to define a specific order of objects in the array. So the most you can do is this:
components:
schemas:
NewFormEntry:
type: array
items:
oneOf:
- $ref: '#/components/schemas/UserInformation'
- $ref: '#/components/schemas/AddressInformation'
- $ref: '#/components/schemas/ContactInformation'
minItems: 3
maxItems: 3
Note that this definition allows arbitrary order of objects in the array and also multiple instances of the same object (e.g. [UserInformation, UserInformation, UserInformation]). You might want to implement additional backend validations to verify the desired order of objects in this array.

Swagger respond with associated objects

I'm using SwaggerHub with OpenAPI 3 to define an API. One route GET /foo/{id], should return the foo object of a given id, with its associated bar objects. The API will return something like: {id: 4, name: 'test', bars: [{id: 53, name: 'barName1'}, {id: 87, name: 'barName2'}]}. I.e. there is a many-to-many relationship between foo and bar.
How do I describe this in OpenAPI 3 syntax? I have tried using the anyOf property. So far I have:
paths:
/foo/{id}:
get:
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Foo'
anyOf:
- $ref: '#/components/schemas/Bar'
But this doesn't appear to show the correct schema in the UI (there is no mention of Bar in the UI).
You don't need anyOf. anyOf indicates an alternative ("either Foo or Bar"), whereas you have a usual nested structure - an object Foo with the property bars that is an array of Bars. This can be described as:
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/Foo'
components:
schemas:
Foo:
type: object
properties:
bars:
type: array
items:
$ref: '#/components/schemas/Bar'
required:
- bars
Bar:
...

Swagger 2.0 request body use both ref and example

In Swagger 2.0 (OpenAPI spec) is there any way to specify an "example" for a request body and also specify the ref? I can do so for a response body. My case is for a certain PUT the body is a ref, but the instance you'd put would differ from the schema's example value.
- name: myObj
in: body
description: The information
required: true
schema:
$ref: '#/definitions/SomeObject'
example: 'some string that conforms to my ref'
In OpenAPI 2.0 - no, not really. $ref overwrites any adjacent keywords, so the example will be ignored. Some tools support x-example or x-examples for parameters, so depending on your tool you might be able to use
- name: myObj
in: body
description: The information
required: true
schema:
$ref: '#/definitions/SomeObject'
x-example:
property1: value1
property2: value2
or
- name: myObj
in: body
description: The information
required: true
schema:
$ref: '#/definitions/SomeObject'
x-examples:
application/json:
property1: value1
property2: value2
or something similar.
What you want is possible in OpenAPI 3.0:
openapi: 3.0.0
...
paths:
/something:
put:
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SomeObject'
example:
property1: value1
property2: value2
This is supported in Swagger UI 3.17.4 and later.

Resources