How to specify constants/enums for properties inside referenced properties in OpenAPI? - openapi

Is it some how possible to specify constants/enums for properties inside referenced complex properties in OpenAPI?
I know for a simple string property I can specify some enum constants which I expect/ allow (as you can see in the example below at property sortOrder.
As you can see in this example I define the TestSearchModel with the property orderBy which is of a referenced type SortModel. SortModel is actually defined in another file of a framework (PS: I have access and the permission to change that framework for my needs). In this SortModel there is the property sortFieldName. I wish I could specify in TestSearchModel that I only allow e.g. ATTR_ONE. Is that possible?
Maybe you can image my use case. I would like to define a search operation which expects an input of type TestSearchModel. With this input it should be possible to define a column/property by with the sorting of the results found should be done.
openapi.yaml:
TestSearchModel:
type: object
properties:
orderBy:
$ref: "#/SortModel"
enum: // allowed values of property sortFieldName in SortModel
- ATTR_ONE
- ATTR_TWO
SortModel:
type: object
properties:
sortFieldName:
type: string
sortOrder:
type: string
enum:
- ASC
- DESC
This should be valid:
{
"orderBy": {
"sortFieldName": "ATTR_ONE",
"sortOrder": "ASC"
}
}
This should end up in an error, because 'ATTR_THREE' is not defined above in the allowed values:
"sortModel": {
"sortFieldName": "ATTR_THREE",
"sortOrder": "ASC"
}
I actually guess that with OpenAPI Spec this kind of specification is not possible. However may be you can provide some recommendations how to handle that.
I tried out the example above. OpenAPI generates the model classes without any error but (some kind of expected) without considering the limitation of the allowed strings for 'order by' property. I wish that an enum would be generated for ATTR_ONE and ATTR_TWO.

It's possible. You'll need to add an extra schema alongside the $ref that defines a property with the same name on the same nesting level.
If you use OpenAPI 3.0.x or 2.0, make sure to wrap the $ref into allOf:
TestSearchModel:
type: object
properties:
orderBy:
allOf:
- $ref: "#/SortModel" # or "#/components/schemas/SortModel" or whatever the correct $ref path is
- properties: # <---
sortFieldName: # <---
enum:
- ATTR_ONE
- ATTR_TWO
SortModel:
type: object
properties:
sortFieldName:
type: string
sortOrder:
type: string
enum:
- ASC
- DESC
In OpenAPI 3.1, you can add keywords directly alongside the $ref:
# openapi: 3.1.0
TestSearchModel:
type: object
properties:
orderBy:
$ref: "#/SortModel" # or "#/components/schemas/SortModel" or whatever the correct $ref path is
properties: # <---
sortFieldName: # <---
enum:
- ATTR_ONE
- ATTR_TWO

The problem with your schema above is that openapi won't read anything after the $ref field. So, the enum value you have placed there is ignored. You can move the enum to your SortModel and it will be available:
TestSearchModel:
type: object
properties:
orderBy:
$ref: "#/SortModel"
SortModel:
type: object
properties:
sortFieldName:
type: string
enum:
- ATTR_ONE
- ATTR_TWO
sortOrder:
type: string
enum:
- ASC
- DESC
If you are trying to reuse the enum, you can do this via a reference, like this
TestSearchModel:
type: object
properties:
orderBy:
$ref: "#/SortFields"
SortModel:
type: object
properties:
sortFieldName:
$ref: "#/SortFields"
sortOrder:
$ref: "#/SortOrderTypes"
SortOrderTypes:
type: string
enum:
- ASC
- DESC
SortFields:
type: string
enum:
- ATTR_ONE
- ATTR_TWO

Related

Combining two choices in a single object

In my service schema I've got a single object that has two choices of properties. Meaning;
Object A needs: property 1 or 2, and property 3 or 4.
To realise this in OAS I'm using an object with an allOf property, which contains two items containing a oneOf property. I don't see a reason why this construction would be illegal. However, when using the swagger editor (https://editor.swagger.io/) and the Swagger Viewer extension in VSCode, it merges the two oneOf properties into a single one, effectively instructing the user to either include property 1, 2, 3 or 4.
One other way to achieve the same is to define a schema for every combination of choice 1 and 2, but this gets very tedious as the amount of options expands (effectively multiplying for every combination of the two choices).
Is my interpretation of the way this should work correct? If not, how can I achieve my goal without the spec becoming too verbose? If yes, I take it this is an issue in both tools I'm using, in that case I'll raise an issue in the respective issue trackers.
Example OAS spec:
openapi: 3.0.3
info:
description: Test API
version: 0.1.0
title: Test API
paths:
/test:
post:
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TestComplexObject'
responses:
'200':
description: OK
components:
schemas:
TestComplexObject:
type: object
allOf:
- type: object
properties:
defaultString:
type: string
- oneOf:
- $ref: '#/components/schemas/TestStr1'
- $ref: '#/components/schemas/TestStr2'
- oneOf:
- $ref: '#/components/schemas/TestStr3'
- $ref: '#/components/schemas/TestStr4'
TestStr1:
type: object
properties:
testString1:
type: string
required: [testString1]
TestStr2:
type: object
properties:
testString2:
type: string
required: [testString2]
TestStr3:
type: object
properties:
testString3:
type: string
required: [testString3]
TestStr4:
type: object
properties:
testString4:
type: string
required: [testString4]

Specify enum value in an inherited object schema Open API

I have the following schemas defined in Open API:
components:
schemas:
ParentModel:
type: object
properties:
type:
type: string
enum: [value1, value2, value3]
ChildModel:
allOf:
- $ref: '#/components/schemas/FieldDefinition'
What I want is to specify a value for the type property of the ParentModel in the ChildModel, from the enum list. Something like:
ChildModel:
allOf:
- $ref: '#/components/schemas/FieldDefinition'
- type: object
properties:
type:
value: text
AnotherChildModel:
allOf:
- $ref: '#/components/schemas/FieldDefinition'
- type: object
properties:
type:
value: text
I know that I could define that type attribute in every model, but I would prefer to do it that way to show all the possible values. Any idea if this is possible at al?

Define Kubernetes Custom Resource requiring one of the following fields or no fields

I try to define a new Custom Resource, requiring it to have one of (1) field A, (2) field B, or (3) empty body.
For example: {A: 1}, {B: 1}, {} are OK, but {A:1, B:2} is not.
Here is the definition of my Custom Resource in form of OpenApi schema:
foo:
type: object
properties:
a:
type: int
b:
type: int
oneOf:
- required: ["a"]
- required: ["b"]
# no sure how to include the empty body
How should I include the empty body in the oneOf constraint?
OpenAPI 3.1
You can use 'null' (with quotes).
oneOf:
- type: 'null'
Or an object with a property of type null.
oneOf:
- NullObjectExample:
type: object
properties:
prop1:
type: 'null'
OpenAPI 3.0
There is no null type, but you can use a nullable string. You may want to add a description stating this is expected to be null at all times.
oneOf:
- type: string
nullable: true
Or again, an object with a nullable string property.
oneOf:
- NullObjectExample:
type: object
properties:
prop1:
type: string
nullable: true
Why No Empty Object
In addition to not making intent clear, this presents a possible security vulnerability. See this page for an explanation. In short:
If you do not clearly define the schema and you leave properties of a JSON payload empty, you effectively allow attackers to pass in any data. This means that you are opening your backend to various attacks, such as SQL injection.

How to discriminate on multiple properties in an OpenAPI schema?

Here the documentation explains how to define discriminators when an OpenAPI schema is dependent on the value of a property. In my own project, I have a schema that is dependent on the values of two properties, not just one. I wonder whether there is any way to model that in an OpenAPI file?
Let's say we have a list of requests with two required enum properties:
requestType: It could be either of these values:
New
Old
periodType: It could be either of these values:
Temporary
Permanent
The values of the rest of properties are somehow dependent on the values of these 2 fields. So there are 4 possible schemas which we want to discriminate them based on these 2 fields. One possible solution that came to my mind was to use a nested structure like this:
ListResponse:
type: array
items:
oneOf:
- $ref: '#/components/schemas/NewRequestResponse'
- $ref: '#/components/schemas/OldRequestResponse'
discriminator:
propertyName: requestType
mapping:
'New':
oneOf:
- $ref: '#/components/schemas/NewTemporaryRequestResponse'
- $ref: '#/components/schemas/NewPermanentRequestResponse'
discriminator:
propertyName: periodType
mapping:
'Temporary': '#/components/schemas/NewTemporaryRequestResponse'
'Permanent': '#/components/schemas/NewPermanentRequestResponse'
'Old':
oneOf:
- $ref: '#/components/schemas/OldTemporaryRequestResponse'
- $ref: '#/components/schemas/OldPermanentRequestResponse'
discriminator:
propertyName: periodType
mapping:
'Temporary': '#/components/schemas/OldTemporaryRequestResponse'
'Permanent': '#/components/schemas/OldPermanentRequestResponse'
uniqueItems: true
But seemingly this is not a valid schema. So, how could it be done?

go-swagger injects digits into properties names

The models.yaml file I have is:
baseStorePatch:
title: Store
type: object
required:
- scalePolicy
properties:
scalePolicy:
$ref: "#/definitions/scalePolicy"
StorePatch:
allOf:
- $ref: "#/definitions/baseStorePatch"
- type: object
properties:
However, when I use go-swagger to generate the clients, the output is:
type StorePatch struct {
ScalePolicy *StorePatchAO0ScalePolicy `json:"scalePolicy,omitempty"`
}
Why the go-swagger auto generate StorePatchAO0 as the prefix? And how to get rid of it?