Model composition in swagger spec without additional nesting layer - swagger

If I have the following example where Settings definition is embedded in Thing via composition:
definitions:
Settings:
properties:
foobar:
type: number
format: double
boofar:
type: string
Thing:
properties:
allOf:
$ref: '#/definitions/Settings'
name:
type: string
If I define a method to POST a Thing in editor.swagger.io, it ends up constructing JSON that looks like this:
{
settings: {
foobar: 1,
boofar: "text here"
},
name: "some name"
}
I want to embed a model definition with composition but without the additional nested property definition -- is this possible? This is the JSON structure I would like to have for Thing:
{
foobar: 1,
boofar: "text here",
name: "some name"
}
Is there a way to achieve this?

Your example do not really use composition as allOf is a property.
allOf is supposed to be on the root of the definition and it's an array of schema (reference or inline).
Here's the proper way to use allOf for your example:
swagger: '2.0'
info:
title: API
version: 1.0.0
paths:
/thing:
get:
responses:
200:
description: OK
schema:
$ref: '#/definitions/Thing'
definitions:
Settings:
properties:
foobar:
type: number
format: double
boofar:
type: string
Thing:
allOf:
- $ref: '#/definitions/Settings'
- properties:
name:
type: string
Resulting rendering in SwaggerUI:

Related

How to use ref and other fields in the request body?

My use case in the root level json there are 100 fields and out of those 100 fields 90 fields are common and the remaining 10 fields varies for different API's, I need to specify this 90 fields in a global space and on top of that I need to put the 10 different fields
SAMPLE
POST localhost:3000/api/v1/people
{
name: "", age: "", father_name: ""
//other 90 fields
}
POST localhost:3000/api/v1/student
{
//all fields of people and the below fields.
department_name:"", courses_enroled: ""
}
POST localhost:3000/api/v1/teacher
{
//all fields of people and the below fields.
yoe: "", //assume some specific fields
}
I need to define people payload in global space and in student API, I need to ref it.
How to do this in swagger.
whenever I use ref, it replaces al other fields in the same level.
You can extend existing definition in Swagger 3 and higher (not sure which version you are using). Example in yaml (not sure what you use):
definitions:
Response:
description: "Response Object"
type: object
properties:
success:
description: "If action was successful or not"
type: boolean
example: true
message:
description: "Action message"
type: string
example: "Some message"
data:
description: "Response data"
type: Any
nullable: true
ErrorResponse:
allOf:
- $ref: "#/definitions/Response"
- type: object
properties:
success:
example: false
message:
example: "Error message"
data:
example: null

How to define in swagger spec either of two properties are not null and required

I have a requirement to have two properties in the payload say property1 and propert2. Both are array type. Condition is, that either both can have values, or only one of them will be non-null. But both cannot be null at the same time.
How can I define this requirement in swagger spec, so that I can enforce schema such that both should not be null but any one of them can be null.
Valid Examples:
Ex1--> {"Property1": ["value1"], "Property2": ["value2"]}
Ex2--> {"Property2": ["value2"]}
Ex3--> {"Property1": ["value1"]}
Invalid Example:
{"Property1": [], "Property2": []}
Assuming the object can only contain these two properties (Property1 and/or Property2) and no other properties, your use case can be defined using a combination of object-level minProperties and array-level minItems:
MyObject:
type: object
minProperties: 1 # <-- requires at least one of Property1 or Property2 to be present
properties:
Property1:
type: array
items:
type: string
minItems: 1 # <-----
Property2:
type: array
items:
type: string
minItems: 1 # <-----
If the payload can also contain other properties, the "either Property1 or Property2 must be present" condition can be defined using anyOf + required. This requires OpenAPI 3.x:
# openapi: 3.x.x
MyObject:
type: object
anyOf: # <----------------
- required: [Property1]
- required: [Property2]
properties:
Property1:
type: array
items:
type: string
minItems: 1
Property2:
type: array
items:
type: string
minItems: 1
SomeOtherProperty:
...

How to make swagger examples component with allOf

components:
examples:
J:
value:
name: my name
J2:
value:
allOf:
- $ref: '#/components/examples/J'
- id: 123
Use J2 in response body examples:
responses:
200:
content:
application/json:
examples:
test:
$ref: '#/components/examples/J2'
Current result:
{
"$ref": "#/components/examples/J",
"id": 123
}
Expected result
{
"name": "my name",
"id": 123
}
Related:
https://swagger.io/docs/specification/data-models/oneof-anyof-allof-not/
Swagger schema properties ignored when using $ref - why?
This is not supported.
The value is meant to be the literal value of the example. As a result, value does not support allOf and $ref. OpenAPI does not have a way to merge the values of multiple example components.
You cannot combine at example level but you can combine examples at path level.
This is invalid
components:
examples:
J:
value:
name: my name
J2:
value:
allOf:
- $ref: '#/components/examples/J'
- id: 123
But you can do this
components:
examples:
J:
value:
name: my name
J2:
value:
id: 123
content:
application/json:
schema:
$ref: '#/components/schemas/MyObject'
examples:
objectExample:
allOf :
- $ref: '#/components/examples/J'
- $ref: '#/components/examples/J2'

Error "bad indentation of a mapping entry" in Swagger editor

In the OpenAPI definition below, the parameter definition causes the parser error "bad indentation of a mapping entry". What is wrong? Error at "properties" (last 5th line)
responses:
'200':
description: OK
content:
application/json;charset=UTF-8:
schema:
type: object
properties:
creationTime:
type: string
format: date-time
description: >-
The date and time the response was created in GMT time
with a format of "MM-dd-yyyy HH:mm:ss.SSSZ"
example: '03-12-2019 14:05:35.182-0500'
response:
type: array
description: ''
properties:
recordID:
type: string
maxLength: 20
externalID:
The error occurs because the properties keyword is indented more than its sibling type and description keywords.
response:
type: array
description: ''
properties: # <---- Indentation doesn't match the sibling
# `type` and `description` keywords
However, type: array schemas need items, not properties.
It looks like the response key is either missing some keywords or has extra keywords. The correct definition for response would be:
response:
type: object # <----------
description: ''
properties: # <----------
recordID:
type: string
maxLength: 20
externalID:
...
or
response:
type: array
description: ''
items: # <----------
type: object # <----------
properties: # <----------
recordID:
type: string
maxLength: 20
externalID:
...
depending on what you need.

springdoc-openapi spec generation for inheritance witth generics

I have a Spring Boot (kotlin) project for which I use springdoc-openapi to generate OpenApi 3 spec. My data model looks like so:
open class Animal
data class Cat(val catName: String) : Animal()
data class Dog(val dogName: String) : Animal()
open class Food<T : Animal>
class CatFood : Food<Cat>()
class DogFood : Food<Dog>()
and a simple controller like so:
#GetMapping("/test")
fun test(): Food<out Animal> = DogFood()
for which the generated yaml is:
openapi: 3.0.1
info:
title: OpenAPI definition
version: v0
servers:
- url: http://localhost:8085
paths:
/test:
get:
tags:
- test-controller
operationId: test
responses:
"200":
description: default response
content:
'*/*':
schema:
$ref: '#/components/schemas/FoodAnimal'
components:
schemas:
FoodAnimal:
type: object
The problem here is that my controller can return either DogFood or CatFood, and that is specified in the return type. The schema I would expect to be generated is:
openapi: 3.0.1
info:
title: OpenAPI definition
version: v0
servers:
- url: http://localhost:8085
paths:
/test:
get:
tags:
- test-controller
operationId: test
responses:
"200":
description: default response
content:
'*/*':
schema:
oneOf:
- $ref: '#/components/schemas/FoodAnimal'
- $ref: '#/components/schemas/DogFood'
- $ref: '#/components/schemas/CatFood'
components:
schemas:
FoodAnimal:
type: object
CatFood:
allOf:
- $ref: '#/components/schemas/FoodAnimal'
type: object
DogFood:
allOf:
- $ref: '#/components/schemas/FoodAnimal'
type: object
Is there some way to achieve this?
For inheritance, you just need to add #Schema annotation, on your parent class:
#Schema(
type = "object",
title = "Food",
subTypes = [CatFood::class, DogFood::class]
)
open class Food<T : Animal>
class CatFood : Food<Cat>()
class DogFood : Food<Dog>()
If you need a reponse using oneOf, you will have to add #Response:
#GetMapping("/test")
#ApiResponse(content = [Content(mediaType = "*/*", schema = Schema(oneOf = [Food::class, CatFood::class,DogFood::class]))])
fun test(): Food<out Animal> = DogFood()
I had problems using OpenApi with inheritance for nested properties.
I used JsonSubtype annotations and generics as a workaround.
data class AnimalResponse<FoodResponse>(
val id: UUID,
val eats: FoodResponse
)
#JsonSubTypes(value = [
JsonSubTypes.Type(
value = CatFoodResponse::class,
name = "CAT_FOOD"
), JsonSubTypes.Type(
value = DogFoodResponse::class,
name = "DOG_FOOD"
)])
interface FoodResponse
This will show all types of FoodResponses in AnimalResponse Schema.

Resources