I have this issue, I have created two libraries to define two different types, here they are:
Category.raml
#%RAML 1.0 Library
uses:
- Event: !include Event.raml
- Tournament: !include Tournament.raml
types:
#############################################################################
base:
usage: The base type for a category
properties:
min_age:
description: The minimum age to participate in the category
required: true
type: number
max_age:
description: The maximum age to participate in the category
required: true
type: number
name:
description: The name of the category
required: true
type: string
gender:
description: The gender of the category
required: true
enum:
- male
- female
- mix
tournament:
description: The tournament of the category
required: true
type: Tournament.base
#############################################################################
full:
usage: A category with all of its events
type: base
properties:
events:
description: The events that the category contains
required: true
type: Event.base[]
Tournament.raml
#%RAML 1.0 Library
uses:
- ClubInscription: !include Club.raml
- Category: !include Category.raml
types:
#############################################################################
base:
usage: The base type for the tournament
properties:
name:
description: The name of the tournament
required: true
type: string
date:
description: Date of the tournament
required: true
type: string
available_lanes:
description: Maximum number of lanes in a serie
required: true
type: number
max_swimmer_inscriptions:
description: Maximum number of events a swimmer may be inscripted
required: true
type: number
award_type:
description: The type of awarding used in the competition
required: true
enum:
- points
- medals
- none
state:
description: The current state of the tournament
required: true
enum:
- closed
- open
- finished
#############################################################################
full:
usage: A tournament with all its categories and club inscriptions
type: base
properties:
club_inscriptions:
description: The clubs inscripted in the tournament
required: true
type: ClubInscription.base[]
categories:
description: The categories the tournament has
required: true
type: Category.base[]
Having this, it makes sense having a conflict. I am pretty knew at RAML, so I read somewhere that "uses" should only be used when using something as a parent, but then what should I do to not re-write everything in everywhere in my project (because this happens everywhere in it).
I have thought of defining the base of the types in one file, but it would be just a mix of information that should not be together, I want to know if there is an alternative to "uses" to re-use the types in another file.
Thanks in advance.
The simplest solution is make:
TournamentBase.raml
TournamentFull.raml
CategoryBase.raml
CategoryFull.raml
You will not have circular dependencies.
Related
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]
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
I'm currently attempting to perform validation on input requests.
Models:
PutStepPlanCRUDModel:
description: "The model for PUT StepPlanCRUD"
type: object
$schema: "http://json-schema.org/draft-04/schema#"
required:
- payload
properties:
payload:
type: object
required:
- updated_fields
additionalProperties: false
properties:
updated_fields:
type: object
additionalProperties: false
minProperties: 1
properties:
step_plan_name:
type: string
description: "The name of the step plan"
step_records:
type: object
additionalProperties: false
It appears as thought the required validation is working however the following validations are not:
additionalProperties: false
minProperties: 1
I'd like to be able to allow the two fields step_plan_name, step_records but if the user provides any other field reject it.
How do I ensure this?
Thanks in advance
In short, here's fragment of OpenAPI specification:
# Consider an imaginary Internet Service Provider that needs to limit
# one or multiple customers in different ways: bandwidth (inbound, outbound), media type (text / music / video), volume (total traffic volume, for example, 5 GB).
# per specific website (a user can have different limit for YouTube and Amazon).
# You'll likely want to rename some of the attributes but
#that's not the point (this API is fake and that's the best example I came up with to reproduce the issue).
components:
schemas:
ProviderLimit:
type: object
properties:
name:
type: string
website_id:
type: string
users:
type: array
items:
type: string
description: List of user IDs
minItems: 1
bandwidth:
type: object
$ref: '#/components/schemas/BandwidthLimit'
volume:
type: object
$ref: '#/components/schemas/VolumeLimit'
media:
type: string
enum:
- TEXT
- MUSIC
- VIDEO
BandwidthLimit:
properties:
incoming_speed:
type: string
format: int64
outcoming_speed:
type: string
format: int64
VolumeLimit:
properties:
target:
type: string
format: int64
The question is which approach shall I take:
Merge all the possible limits (bandwith, volume, media), make them all optional, and agree to specify just one of them on the client.
Use oneOf.
# Example of using oneOf
components:
schemas:
ProviderLimit:
type: object
properties:
name:
type: string
website_id:
type: string
users:
type: array
items:
type: string
description: List of user IDs
minItems: 1
limit_type:
type: object
oneOf:
- $ref: '#/components/schemas/BandwidthLimit'
- $ref: '#/components/schemas/VolumeLimit'
- $ref: '#/components/schemas/MediaLimit'
discriminator:
propertyName: type # or something else
It looks like option #2 looks a little bit better but overall one could tell #1 option is somewhat reasonable (it's very simple and doesn't overcomplicate the API). Is there a strong argument to use #2 besides it just looks a little bit better (for example, there's a use case where using #1 might not lead to expected results)?
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?