How to have multiple infinite objects without an array - Open API / Swagger - json

I'm trying to setup an open api spec for the following snippet of JSON:
"test1": {
"1739573957": {
"tester1": 123,
"tester2": "Company"
},
"64903826718": {
"tester1": 123,
"tester2": "Company"
}
"5902849189": {
"tester1": 123,
"tester2": "Company"
}
}
The objects inside test1 have randomized guids and are listed in a way that typically would be an array, but is not. There could potentially be an infinite number of objects inside test 1. Anyone know how to set this up?

test1 is a string-to-object dictionary and can be defined as follows (assuming OpenAPI 3):
components:
schemas:
Tester: # Or however you would name the nested objects
tester1:
type: integer
example: 123
tester2:
type: string
example: Company
...
test1:
type: object
additionalProperties:
$ref: '#/components/schemas/Tester'
# Optional example for the `test1` property
example:
'1739573957':
tester1: 123
tester2: Company
'64903826718':
tester1: 123
tester2: Company
The objects inside test1 have randomized guids
In OpenAPI 3.1, you can use patternProperties instead of additionalProperties to define that the keys inside test1 are numeric strings. Earlier OpenAPI versions don't have a way to define the format of dictionary keys.
# openapi: 3.1.0
test1:
type: object
patternProperties: # <-----
'^\d+$': # <-----
$ref: '#/components/schemas/Tester'

You are looking for the free-form-object:
A free-form object (arbitrary property/value pairs) is defined as:
type: object
This is equivalent to
type: object
additionalProperties: true
and
type: object
additionalProperties: {}
However, if you can change the API, I'd highly recommend to change it to an array of tests or whatever the object defines. Put the id as property into this object and you're good to go. This makes creating DTOs for it a lot easier.

Related

How to add global "pattern" validator to apply for all fields of type "string" in a json schema pattern

I'm using Ajv JSON schema validator.
I'd like to apply a global Special Characters regex validation for all properties of type "string".
I've saw that there is allOf validation that takes an array of condition for example:
allOf: [{maximum: 3}, {type: "integer"}]
But when trying to do something like this:
{
type: 'object',
allof: [{pattern: '[<>%\${}[\]]]'}]
}
It's no working.

Message examples in OpenAPI 3 YAML specification

OpenAPI v3 offers using JSON or YAML format.
I prefer using YAML to create API specifications. YAML's readability is much better for me as an API designer.
However, sometimes I need to embed a message example whose type is object. I usually have the examples in JSON format. So I would do the following:
examples:
singlePet:
summary: Single pet
description: A request containing a single pet
value: |
{
"pets" : [
{
"petType" : "DOG",
"name" : "Ben"
}
]
}
However, such value is a string, not an object, whereas OpenAPI expects an object.
Do we have any options to embed a JSON as an example value in the YAML specification?
Currently, I convert the JSON to YAML and embed the YAML:
examples:
singlePet:
summary: Single pet
description: A request containing a single pet
value:
pets:
- petType: DOG
name: Ben
YAML is a superset of JSON. This means you can use JSON syntax for objects and arrays within a YAML document.
In your first example, you can just remove the | after the value: to keep the example value as an object.
The following are equivalent:
examples:
singlePet:
summary: Single pet
description: A request containing a single pet
value:
{
"pets" : [
{
"petType" : "DOG",
"name" : "Ben"
}
]
}
examples:
singlePet:
summary: Single pet
description: A request containing a single pet
value:
pets:
- petType: DOG
name: Ben
Alternatively, you can use externalValue to point to an external file containing sample JSON.
examples:
singlePet:
summary: Single pet
description: A request containing a single pet
externalValue: 'https://api.example.com/docs/examples/pet.json'

Is it possible to 'inject' reference to a JSON Schema

Considering I need to refer to a json with the following format:
{
"data": {
"type": "ObjectA"
}
}
When I write JSON schema (or more specifically, schema object of OpenAPI Specification v3.0.3) for this json request, I write
components:
schemas:
Data:
type: object
required:
- data
properties:
data:
$ref: '#components/schemas/ObjectA'
ObjectA:
type: object
properties:
type:
type: string
ObjectB:
type: object
properties:
type:
type: string
some_properties:
type: string
... and I refer to it using $ref: '#components/schemas/Data'.
However now there is the other json to deal with, which is very similar to the one above except that the object in data property is not of type ObjectA, it is ObjectB instead.
{
"data": {
"type": "ObjectB",
"some_properties": "which is different from ObjectA"
}
}
Is there a way for me to reuse the schemas for Data above without creating a new schema (so it is like injecting #components/schemas/ObjectA or #components/schemas/ObjectB into Data whenever needed)?
I have considered using oneOf but it does not fit since only a specific object is valid for a specific API endpoint (even though all are under the data property) instead of any one of the available objects.
In your simple example, it seems unnecessary to re-use the simple Data definition. However, assuming your actual structure is more complex you could combine the general attributes with the specific ones via allOf, e.g.
components:
schemas:
BaseData:
type: object
required:
- data
properties:
data:
type: object
properties:
type:
type: string
required:
- type
DataA:
allOf:
- $ref: '#components/schemas/BaseData'
- type: object
properties:
data:
$ref: '#components/schemas/ObjectA'
DataB:
allOf:
- $ref: '#components/schemas/BaseData'
- type: object
properties:
data:
$ref: '#components/schemas/ObjectB'
ObjectA:
type: object
properties:
type:
const: ObjectA
ObjectB:
type: object
properties:
type:
const: ObjectB
some_properties:
type: string
required:
- some_properties
Depending on the actual complexity, the schema might be easier to read/maintain if the shared parts are simply duplicated.

Swagger schema with additionalProperties fails

I'd like to post a JSON object within the body of a REST API call. The attribute dataof this DATA object contains a mandatory timestampattribute and then a series of various attributes depending on the source of the Data object. As far as I understood additionalPropertiesis meant for this and defaults to falseor specifies the schema object for every non-defined attribute.
Following Swagger YAML
/my/path:
post:
tags: [Tag]
description: Description
parameters:
- name: data
in: body
description: The actual data.
required: false
type: object
schema:
$ref: "#/definitions/Data"
definitions/
Data:
type: object
properties:
source:
type: string
data:
type: object
properties:
timestamp:
type: string
format: date-time
additionalProperties:
type: string
should pass both objects send:
{
"source": "A",
"data": {
"timestamp": "2016-10-26T01:12:40.329Z",
}
}
and:
{
"source": "B",
"data": {
"timestamp": "2016-10-26T01:12:40.329Z",
"newProp":"newValue"
}
}
However all I receive is a validation Error:
ValidationError: child "data" fails because ["test" is not allowed]
Is there anything I'm doing wrong or am I misinterpreting the attribute described at the docs:
http://swagger.io/specification/
I'm not sure if your solution got your past the problem. I see a few differences from your original problem schema:
timestamp now uses date instead of datetime format.
timestamp is now required.
additionalProperties is set to true.
However, there's a set of obscure limitations in Swagger with respect to additionalProperties, which we've documented in detail here.
Essentially, while your original schema is perfectly valid according to the Swagger specification, the swagger-core Java library won't process it correctly. It will discard either your explicitly defined timestamp property, or will discard additionalProperties.
The fix, surprisingly, is to extract the embedded schema for the data property to its own top-level schema definition:
definitions:
Data:
type: object
properties:
source:
type: string
data:
$ref: "#/definitions/DataValues"
DataValues:
type: object
properties:
timestamp:
type: string
format: date-time
additionalProperties:
type: string
I think your revised schema won't work correctly, because additionalProperties boolean values of true or false are ignored by swagger-core. Apparently this was an oversight in the specification; Swagger didn't intend to support this aspect of JSON Schema.
I actually figured it out myself, for reference:
definitions/
Data:
type: object
properties:
source:
type: string
data:
required:
- timestamp
type: object
properties:
timestamp:
type: string
format: date
additionalProperties: true

Swagger Yaml schema definition for object without a fixed property list

I am implementing an API-first application with the help of Swagger. One of the most important objects to be returned is a DICOM object, which returns a collection of attributes with flexible names, for example:
{
"00080005": {"vr":"CS","Value":["ISO_IR 100"]},
"00080020": {"vr":"DA","Value":["20160602"]},
"00080030": {"vr":"TM","Value":["171855.7490"]},
"00080050": {"vr":"SH","Value":["1234"]},
"00080090": {"vr":"PN","Value":[{"Alphabetic":"Parikh MD^Anush^M"}]}
}
So I cannot know the name of all the attributes in advance (00080005, 00080030, etc.) although the file structure is very uniform.
My concrete question is: what would be the schema definition for such JSON document.
I have tried the following without success:
definitions:
DicomMetadataJson:
type: object
patternProperties:
^\d{8}:
type: object
but the Swagger Editor returns an error like:
code: "OBJECT_ADDITIONAL_PROPERTIES"
message: "Additional properties not allowed: patternProperties"
description: "A deterministic version of a JSON Schema object."
OpenAPI (fka. Swagger) use only a subset of JSON Schema v4 which, unfortunately, do not propose patternProperties.
But given the provided example is a map, you can describe it using additionalProperties:
swagger: "2.0"
info:
version: 1.0.0
title: Hashmap
paths: {}
definitions:
DicomMetadataJson:
additionalProperties:
properties:
vr:
type: string
Value:
type: array
items:
type: string
The key is not defined and is supposed to be a string (therefore you cannot enforce it's format).
Note that SwaggerUI Swagger UI do not render them for now.The issue is tracked here https://github.com/swagger-api/swagger-ui/issues/1248
In the meanwhile you can use this trick define a non required property (default in the example below) of the same type of the map's objects and give some hint within the description:
swagger: "2.0"
info:
version: 1.0.0
title: Hashmap
paths: {}
definitions:
MetaData:
properties:
vr:
type: string
Value:
type: array
items:
type: string
DicomMetadataJson:
description: 'A <string,MetaData> map, default key is only for documentation purpose'
properties:
default:
$ref: '#/definitions/MetaData'
additionalProperties:
$ref: '#/definitions/MetaData'
Concerning the quote The schema exposes two types of fields. Fixed fields, which have a declared name, and Patterned fields, which declare a regex pattern for the field name. Patterned fields can have multiple occurrences as long as each has a unique name., it concerns the format of the OpenAPI specification itself and not the objects used by the API described with an OpenAPI specification.