OpenApi - how to specify response json with unknown attribute names - json

I have an API that returns rows of data based on a request. The rows are JSON elements containing name:value pairs. However, the attribute names (and datatypes of the values) need to be fluid and undefined in the spec.
For example:
{
"row_id": 1234,
"data": {
"foo": "bar",
"date": "2019-07-31",
"some_number": 5
}
}
In this example, the attributes 'row_id' and 'data' are the only fixed things. All the name:values pairs inside the data element can be anything.
I believe I can use open api additionalProperties to describe this, but no examples I can find tell me how or confirm that this is correct.
Does anyone have an idea how to do this or can point me in the right direction?

It looks like what I was looking for was:
recordData:
type: object
additionalProperties: {}
type: object defines it as a general object, and additionalProperties: {} says the object contains properties that have not been specifically defined.
The docs I finally located also say that additionalProperties: true would also work.

Related

OpenAPI path/query parameters nested structure serialization

In the OpenAPI docs about parameter serialization there's a short section about how to serialize query, path, header and cookie parameters with different styles. The schema of these parameters are described as OpenAPI flavoured json schema, which allows infinite nesting of objects and arrays. I haven't found any mention about how to deal with these in the docs:
https://swagger.io/docs/specification/serialization/
Let's assume the JSON schema provided for any of the parameters is like this:
{
"type": "object",
"properties": {
"foo": {
"type": "object",
"properties": {
"bar": "string"
}
}
}
}
Meaning it allows structures in JSON such as:
{
"foo": {
"bar": "hello"
}
}
Or similar concept with arrays that are nested:
{
"type": "array",
"items": {
"type": "array",
"items": {
"type": "string"
}
}
}
Which allows structures like this (at least in JSON):
[["a"], ["b"]]
My question:
Is this allowed for path, query, etc parameters according to OpenAPI spec?
In case it is, are there any docs on how to serialize these in the different styles the spec allows?
In case it is not, is this mentioned anywhere in official docs?
I'm asking this because I'm working on tooling that needs to be compatible with the OpenAPI spec, and I'd like to know what can I expect here as parameter formats. I'm fully aware that having giant nested objects and trying to serialize them in a url is not the smartest idea. However I'm interested in what the OpenAPI spec allows.
Short answer: It's undefined behavior.
Most OpenAPI serialization styles are based on RFC 6570, which provides guidance only for:
primitive values,
arrays of primitives,
simple non-nested objects (with primitive properties).
In case of other types of values (nested objects, objects containing arrays, nested arrays, arrays of objects) the behavior is undefined.
Similarly, OpenAPI's own deepObject style is currently defined only for simple objects but not for arrays or nested objects. Here are some related comments from the OpenAPI Specification authors/maintainers:
By the way, is there a reason we couldn't have deepObject work for arrays too? [...]
Darrel: Supporting arrays as you describe was my intent. I was supposed to find some canonical implementation to use as a guideline for the behavior, but didn't get around to it.
Ron: If we end up supporting the exploded array notation, it needs to be clear that the first index is 0 (or 1, or -1, or whatever).
(source)
Ron: when we defined deepObject in the spec, we explicitly chose to not mention what happens when the object has several levels in it, but in our conversations we went with 'not supported'. ​
(source)
There's an existing feature request to extend deepObject to support arrays and nested structures:
Support deep objects for query parameters with deepObject style
OpenAPI spec 3.0/3.1 supports parameter serialization in JSON format. It's just mentioned at the end of the page you referred.
Other Serialization Methods
schema vs content
From OpenAPI spec 3.0.3:
For more complex scenarios, the content property can define the media
type and schema of the parameter. A parameter MUST contain either a
schema property, or a content property, but not both.
Below OpenAPI snippet shows how to define the query parameters that have the desired structure in the question:
parameters:
- name: objParam
in: query
content:
application/json:
schema:
type: object
properties:
foo:
type: object
properties:
bar:
type: string
- name: nestedArray
in: query
content:
application/json:
schema:
type: array
items:
type: array
items:
type: string

json schema validate the value of one property against the value of another property

Let's say I have the follow Json Schema
{
'type': 'object',
'properties': {
'MinimumNumber': {'type':'number'},
'MaximumNumber': {'type':'number'}
},
'required': ['MinimumNumber', 'MaximumNumber'],
'additionalProperties': false
}
How do I validate that the value of MaximumNumber is higher than the value of MinimumNumber?
invalid object
{
MinimumNumber: 10,
MaximumNumber: 5
}
valid object
{
MinimumNumber: 5,
MaximumNumber: 10
}
This is a frequently asked question, but no, there is no way in JSON Schema to compare one section of your data against another section. You can do it manually by editing your schema to contain a portion of your data, e.g. via a template.
#Ether is correct in saying that there is no solution for this with pure JSON Schema. However, there are now vocabularies. I've written one that allows you do just this.
Currently there's only my .Net implementation, but as draft 2020-12 is adopted, this may see more use across implementations in other frameworks.

Swagger parse associative array with undefined properties

I'm trying to figure out how to achieve for Swagger to parse an associative array with an undefined number of values.
I have similar cases, with the difference that these other cases are totally regular (I know in advance all the properties' names). However, I might not know (actually I don't want to know) which could be the name of the values in these case.
Example of JSON that has an associative array with an undefined number of language codes. Each language code key, has an array of undefined translations, with a key and a value for each translations. "DESCRIPTION" and "ACCESS_ON_FOOT" in this case are the keys of the translations. But there could be others and I don't want to know all of them. It's supposed to be dynamic.
{
"ca": {
"DESCRIPTION": "Catalan description",
"ACCESS_ON_FOOT": "Catalan Access on foot"
},
"en": {
"DESCRIPTION": "English Description",
"ACCESS_ON_FOOT": "English Access on foot"
},
"es": {
"DESCRIPTION": "Spanish Description",
"ACCESS_ON_FOOT": "Spanish Access on foot"
}
}
The thing is that I don't know how to specify this example of undefined language codes as the values of an object.
I my other case, I made it work easily, since I knew which values I had. I of course could add "ca", "en" and "es" as properties of type array. But if I add languages, I should come back to the Swagger spec and make it again, and my idea is to make the process of adding a new language totally decoupled of the API spec.
Is there a way of defining in Swagger 2.0 an undetermined set of properties?
UPDATE
It seems this could be a possible solution to the issue I'm having to parse this JSON:
Translations:
type: "object"
additionalProperties:
type: object
additionalProperties:
type: string
The additionalProperties option seems to be the right one for associative arrays. At least according to the specification:
https://swagger.io/docs/specification/data-models/dictionaries/
The Swagger Editor (https://editor.swagger.io/) is showing to me the same JSON format I described, but I still get an empty output in the generated client.
After doing more research, it seems unclear to me that associative arrays are working in Swagger 2.0. I'd love to make this work. At the end I have opted to go for a different alternative, and made my API endpoint return a slightly different result.
I had an associative array with 2 dimensions and the value stored.
Now I have a unidimensional array with 3 properties:
Translations:
type: "object"
properties:
language_code:
type: "string"
type:
type: "string"
content:
type: "string"
As Translations is in the definitions set, I can easily include an array of Translations in the response of the endpoint like that:
responses:
200:
description: "successful operation"
schema:
type: "array"
items:
$ref: "#/definitions/Translations"
This worked like a charm.
Swagger seems to work very nicely, as long as you don't have cases where there is too much freedom. When that happens, you'd need to change your mind and find a different alternative to do things.
P.S. Start first with your API definition, (like you would do with tests and then code). So first API definition, then tests and then code.

Is this valid JSON? Does root of a JSON stream/file have to be a single object or array?

Is the following valid JSON?
["start", 1234]
["open", 97]
I read the official standard twice and I wasn't able to find anything that said that this isn't valid JSON.
Interesting question. Couldn't help but research a bit. RFC-7159 explicitly refers to ECMA-404, which says:
A JSON value can be an object, array, number, string, true, false, or null
So basically, ECMA-404 tells us that a JSON value can be either of the above, but only a single one of them. Given your example:
["start", 1234]
["open", 97]
That'd not be considered valid JSON together, at it is not an array, but two arrays, and therefore two JSON values and not one.

JSON Schema: required field

Im trying to use json-schema validation at some project, and want to ask about the "required" field.
In current doc there is a specifiaction:
The value of this keyword MUST be an array. This array MUST have at least one element. Elements of this array MUST be strings, and MUST be unique.
But in another examples in the web, i can find something like:
"properties": {
"foo": {
"required": true
}
}
What is a valid way to define required fields?
In version 3 of JSON Schema it was a boolean.
In the latest version, 4, it is now an array of strings.
The validator you are using may still be implementing the old specification.