We are looking at using CloudEvents as a message envelope for events generated in our system, and defining those messages using AsyncAPI.
We are using the CloudEvents type property to identify each event type, with a different data property schema for each type. Whilst I have worked out how to define the individual event structures using AsyncAPI, I can't identify how to set the type property to the value required for that event type.
What would seem a mis-use of the enum keyword is the only way so far that I've been able to associated the event type to the property, as shown in the example below. Is there an accepted pattern for achieving the definition of these fixed properties within the AsyncAPI specification?
channels:
user:
subscribe:
message:
payload:
$ref: '#/components/schemas/firstEventPayload'
components:
schemas:
firstEventPayload:
type: object
allOf:
- $ref: 'https://raw.githubusercontent.com/cloudevents/spec/v1.0.1/spec.json'
properties:
type:
type: string
enum: [test.cloud.event.new-user]
data:
type: object
properties:
userId:
type: string
format: uuid
email:
type: string
format: email
Credit to developers.redhat.com for the cloudevent/spec $ref
In JSON Schema (AsyncAPI Schema is a superset of it) you can also use const like:
type:
type: string
const: test.cloud.event.new-user
Related
Is there any way to name a custom property 'type', given that there already exists a special 'type' property which is a reserved keyword.
components:
schemas:
element:
type: object
properties:
name:
type: string #type here is the keyword
type: #type here is the actual name of the property!
type: string
enum:
- radiogroup
- checkbox
The back-end system which produces the JSON messages cannot be modified to rename the property.
Thanks.
Reserved keywords can be used as property/parameter names in all OpenAPI versions.
The only issue with your example is that YAML indentation is off, other than that your object and property definitions are perfectly valid.
components:
schemas:
element:
type: object
properties:
name:
type: string
type: # <----- yes, property name can be "type"
type: string
enum:
- radiogroup
- checkbox
I use kotlin + Jersey and swagger documentation generator with the approach code first.
I have two DTO
enum class DataType {
FIRST, SECOND;
}
data class Data1(type: DataType)
data class Data2(type: DataType)
gradle dependency
implementation("io.swagger.core.v3:swagger-jaxrs2-jakarta:2.2.6")
Expected result for documentation:
components:
schemas:
DataType:
type: string
enum: [ FIRST, SECOND ]
Data1:
type: object
properties:
type:
$ref: '#/components/schemas/DataType'
Data2:
type: object
properties:
type:
$ref: '#/components/schemas/DataType'
Actual result
components:
schemas:
Data1:
type: object
properties:
type:
type: string
enum: [ FIRST, SECOND ]
Data2:
type: object
properties:
type:
type: string
enum: [ FIRST, SECOND ]
The problem is, that if any client reuses schema to generate classes for his own app, he gets two separate enum classes for the type property.
Q: How to make generator to detect that it is the same enum and extract it to separate type reference?
Ok, I found one approach myself
import io.swagger.v3.core.jackson.ModelResolver.SET_PROPERTY_OF_ENUMS_AS_REF
init {
System.setProperty(SET_PROPERTY_OF_ENUMS_AS_REF, "any value")
}
The other way is to implement a custom ModelResolver, but the class implementation looks quite complicated
UDPATE
Just noticed, that public static boolean enumsAsRef = System.getProperty("enums-as-ref") != null; in ModelResolver is not final. So we can do even simpler
init {
io.swagger.v3.core.jackson.ModelResolver.enumsAsRef = true
}
It's possible to define a parameter into the parameters section, under components section into an OPEN API sheet.
At the same time it's possible to reference that parameter into a path, under the responses section.
What I want to do, it's E.G. having a parameter "include" of type array override only the section enum of the schema part, from the paths section referencing the one in the components one.
It seems the allOf directive it's not allowed in that context, is there a way to do that?
Probably I just need an example.
Example:
In the components.parameters section:
- name: include
in: query
description: relationships to include
type: array
style: form
explode: true
schema:
type: array
items:
type: string
In the paths. .. parameters section:
- name: include
in: query
description: relationships to include
type: array
style: form
explode: true
schema:
type: array
items:
type: string
enum: [legs, owner]
I would like to redefine only the enum section and not
My API has a default envelope for all collection-type resources, like the following:
{
"data": [{},{},{}],
"self": "http://api-url/members",
"total": 120,
"limit": 10,
"offset": 0
}
Is it possible to define this using RAML? Inside a resourceType? How?
It depends on what you are using for specifying your API's entities:
JSON Schema Draft 3 - Create a base schema with these common fields and use the extends mechanism in each concrete schema,
JSON Schema Draft 4 - Create a shared schema with these common fields and use the allOf mechanism to mix it in each concrete schema,
RAML 1.0 Types - Create a common type and refer to it in each concrete type via the type attribute.
With RAML 1 you can use types and inheritance to define your envelope and data types. And resource types for applying to all collection-type resources, for example:
types:
person:
type: object
properties:
name:
age:
car:
type: object
properties:
model:
brand:
envelop:
type: object
properties:
data: person[] | car[]
self: string
total: integer
limit: integer
offset: integer
resourceTypes:
- collection:
get:
responses:
200:
body:
type: envelope
/users:
type: collection
get:
More info here, here and here
I have an API where I post a set of object to the server, differentiated by type, where each type has some different parameters. The commands are structured like so:
{
"type": <command-name>,
"args": {
<command-specific args>
}
}
For example, these may be two possible commands:
{
"type": "Flooblinate",
"args": {
"intensity": "High",
"frequency": "Every blue moon"
}
}
{
"type": "Blagostrate",
"args": {
"temperature": 34.5,
"darkMatter": true
}
}
How can I specify this in Swagger? I can specify an enum for "type", but how do I say ""args" is one of these possible objects"?
I've checked out the docs but nothing stands out. The most promising one was allOf because it displayed nicely in the editor (pastebin, paste into the online editor):
definitions:
Product:
type: object
allOf:
- type: object
title: Flooblinate
properties:
intensity:
type: string
frequency:
type: string
- type: object
title: Blagostrate
properties:
temperature:
type: number
darkMatter:
type: boolean
Which looks like this:
However, this isn't semantically what I need, and, not surprisingly, in the online viewer (that one's not set up for my test case, not sure how to link up a local file easily), they are presented as if all the fields appear at the same time, which is of course what allOf means:
What's the proper way to represent this with Swagger?
According to input from Ron on the google group, what I want is to use the discriminator property:
definitions:
Product:
type: object
discriminator: type
properties:
type: string
required: [type]
Flooblinate:
allOf:
- $ref: '#/definitions/Product'
- type: object
properties:
intensity:
type: string
frequency:
type: string
Blagostrate:
allOf:
- $ref: '#/definitions/Product'
- type: object
properties:
temperature:
type: number
darkMatter:
type: boolean
Semantically this means what I want it to mean. I should specify $ref: '#/definitions/Product' wherever the API accepts or returns any one of Flooblinate or Blagostrate. Note this requires a field (called type here) on the objects to act as the discriminator.
I thought this may be the approach, but the tools didn't show what I expected. However:
That's because the tools are not 100% in support of the discriminator yet - however, that's the right way to describe your use case.
Once you define the discriminator in the top level model, anything that 'allOf's it will be considered a viable option, and indeed you're refer to the top level model for usage.