Swagger parse associative array with undefined properties - json

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.

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

OpenApi - how to specify response json with unknown attribute names

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.

OpenAPI query string parameter with list of objects

I am trying to document with OpenAPI a query string which look like
filtered[0][id]=code&filtered[0][value]=12345
and contains a list of object with properties id and value.
My yaml documentation looks like the following
parameters:
- name: filtered
in: query
description: filters to be applied
explode: true
style: deepObject
schema:
type: array
items:
properties:
id:
description: name of the field to be filtered
type: string
value:
description: value of the filter
type: object
The problem is the following: it looks like the style: deepObject option works only for one level, and not at the second level where my objects actually are. That is, it expects a query string like
?sorted[0]=%7B%0A%20%20%22id%22%3A%20%22string%22%2C%0A%20%20%22value%22%3A%20true%0A%7D
with the object not serialized as an array with id and value keys.
Is there a way to solve this?
This is not possible as of OpenAPI 3.1
OpenAPI 3.0/3.1 Specifications currently defines the deepObject behavior only for simple objects (with primitive properties) such as
{
"id": 5,
"name": "Bob"
}
but not for arrays and not for nested objects.
Since the behavior for arrays and nested objects is not defined, there's really no way to describe your query string. Technically, the only way would be to define filtered[0][id], filtered[0][value], etc. as individual query parameters.
If you are designing a new API (rather than describing an existing one), consider passing the array of objects in the request body instead.
As name implies, :), deepObject style only "provides a simple way of rendering nested objects", not arrays. At the least according to Version 3.0.1 it applies only to objects.
Note that even nested objects might be not yet supported by tools because the specification "does not provide such examples".
So your format is not compatible with Open API, yet may be you can define you query as parameters which follow a regex. I such cases usually I do my best yet provide some explanation
https://swagger.io/specification/
Update. Apparently, after somebody demanded a 'descriptive error' message for nested objects, a patch (PR) to support nested objects was suggested at https://github.com/swagger-api/swagger-js/pull/1450 . Regretfully it was decided not to incorporate this feature, and PR 1450 was rejected.
I know it's an old question, but starting open api 3 there is a support for what you looking for
https://swagger.io/docs/specification/describing-parameters/#schema-vs-content.
it was reported as a bug that was fixed with openapi generator 6.0.1 +
https://github.com/OpenAPITools/openapi-generator/issues/4808
parameters:
- in: query
name: filter
content:
application/json:
schema:
schema:
$ref: "#/components/schemas/Filter"

Source of documentation for a standard JSON document structure?

I am working on a (.NET) REST API which is returning some JSON data. The consumer of the API is an embedded client. We have been trying to establish the structure of the JSON we will be working with. The format the embedded client wants to use is something I have not seen before in working with JSON. I suggested that it is no "typical" JSON. I was met with the question "Where is 'typical' JSON format documented"?
As an example of JSON I "typically" see:
{
"item" : {
"users": [ ... list of user objects ... ],
"times": [ ... list of time objects ...],
}
}
An example of the non-typical JSON:
{
"item" : [
{
"users": [ ... list of user objects ... ]
},
{
"times": [ ... list of time objects ...]
},
]
}
In the second example, item contains an array of objects, which each contain a property whose value is an array of entities. This is valid JSON. However, I have not encountered another instance of JSON that is structured this way when it is not an arbitrary array of objects but is in fact a set list of properties on the "item" object.
In searching json.org, stackoverflow.com and other places on the interwebs I have not found any guidelines on why the structure of JSON follows the "typical" example above rather than the second example.
Can you provide links to documentation that would provide recommendations for one format or the other above?
Not a link, but just straightforward answer: Items are either indexed (0, 1, 2, ...) or keyed (users, times). No matter what software you use, you can get at indexed or keyed data equally easily and quickly. But not with what you call "non-typical" JSON: To get at the users, I have to iterate through the array and find one dictionary that has a key "users". But there might be two or more dictionaries with that key. So what am I supposed to do then? If you use JSON schema, the "non-typical" JSON is impossible to check. In iOS, in the typical case I write
NSArray* users = itemDict [#"users"];
For the non-typical JSON I have to write
NSArray* users = nil;
for (NSDictionary* dict in itemArray)
if (dict [#"users"] != nil)
users = dict [#"users"];
but that still has no error checking for multiple dicts with the key "users". Which is an error that in the first case isn't even possible. So just tell them what the are asking for is rubbish and creates nothing but unnecessary work. For other software, you probably have the same problems.

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.