The API I'm trying to describe has a structure where the root object can contain an arbitrary number of child objects (properties that are themselves objects). The "key", or property in the root object, is the unique identifier of the child object, and the value is the rest of the child object's data.
{
"child1": { ... bunch of stuff ... },
"child2": { ... bunch of stuff ... },
...
}
This could similarly be modeled as an array, e.g.:
[
{ "id": "child1", ... bunch of stuff ... },
{ "id": "child2", ... bunch of stuff ... },
...
]
but this both makes it structurally less clear what the identifying property is and makes uniqueness among the children's ID implicit rather than explicit, so we want to use an object, or a map.
I've seen the Swagger documentation for Model with Map/Dictionary Properties, but that doesn't adequately suit my use case. Writing something like:
"Parent": {
"additionalProperties": {
"$ref": "#/components/schemas/Child",
}
Yields something like this:
This adequately communicates the descriptiveness of the value in the property, but how do I document what the restrictions are for the "key" in the object? Ideally I'd like to say something like "it's not just any arbitrary string, it's the ID that corresponds to the child". Is this supported in any way?
Your example is correct.
how do I document what the restrictions are for the "key" in the object? Ideally I'd like to say something like "it's not just any arbitrary string, it's the ID that corresponds to the child". Is this supported in any way?
OpenAPI 3.1
OAS 3.1 fully supports JSON Schema 2020-12, including patternProperties. This keyword lets you define the format of dictionary keys by using a regular expression:
"Parent": {
"type": "object",
"patternProperties": {
"^child\d+$": {
"$ref": "#/components/schemas/Child"
}
},
"description": "A map of `Child` schemas, where the keys are IDs that correspond to the child"
}
Or, if the property names are defined by an enum, you can use propertyNames to define that enum:
"Parent": {
"type": "object",
"propertyNames": {
"enum": ["foo", "bar"]
},
"additionalProperties": {
"$ref": "#/components/schemas/Child"
}
}
OpenAPI 3.0 and 2.0
Dictionary keys are assumed to be strings, but there's no way to limit the contents/format of keys. You can document any restrictions and specifics verbally in the schema description. Adding schema examples could help illustrate what your dictionary/map might look like.
"Parent": {
"type": "object",
"additionalProperties": {
"$ref": "#/components/schemas/Child"
},
"description": "A map of `Child` schemas, where the keys are IDs that correspond to the child",
"example": {
"child1": { ... bunch of stuff ... },
"child2": { ... bunch of stuff ... },
}
If the possible key names are known (for example, they are part of an enum), you can define your dictionary as a regular object and the keys as individual object properties:
// Keys can be: key1, key2, key3
"Parent": {
"type": "object",
"properties": {
"key1": { "$ref": "#/components/schemas/Child" },
"key2": { "$ref": "#/components/schemas/Child" },
"key3": { "$ref": "#/components/schemas/Child" }
}
}
Then you can add "additionalProperties": false to really ensure that only those keys are used.
Related
So maybe I'm trying to go into too much detail in my descriptor, but here's my use case. While defining the schema of the object that is returned in the response body for my API, I have one property of the object the value of which is an object with variable properties, so I am using the additionalProperties descriptor.
{
"type": "object",
"additionalProperties": {
"type": "string"
}
}
However instead of describing the type of the values in this variable keyed object as string, I would like to describe them more precisely, seeing that the string is actually a pipe delimited serialization of an array. Example:
{
"property1": {
"variableProperty1": "info1|info2|info3",
"variableProperty2": "info1|info2|info3"
}
}
Is there any way of describing this pipe-delimited serialization? Something like:
{
"type": "object",
"additionalProperties": {
"type": "array",
"explode": false,
"encoding": {
"style": "pipeDelimited"
}
},
}
Or is this only possible for query parameters?
SPEC provides next example how to identify schema:
{
"$id": "http://example.com/root.json",
"definitions": {
"B": {
"$id": "other.json",
},
}
}
#/definitions/B
http://example.com/other.json
http://example.com/other.json#
http://example.com/root.json#/definitions/B
But how is it identified if root schema root.json would be defined under /some/path instead of / path?
{
"$id": "http://example.com/some/path/root.json",
"definitions": {
"B": {
"$id": "other.json",
},
}
}
How other.json should be identified?
http://example.com/other.json
or:
http://example.com/some/path/other.json
And which part of SPEC defines this?
Schemas can be identified by any URI that has been given to them,
including a JSON Pointer or their URI given directly by "$id". In all
cases, dereferencing a "$ref" reference involves first resolving its
value as a URI reference against the current base URI per RFC 3986
[RFC3986].
(Dereferencing section)[http://json-schema.org/latest/json-schema-core.html#rfc.section.8.3.2] of the spec.
The "base URI" is defined in RFC 3986 which is referenced in the JSON Schema specification.
It's not super easy to understand because it's quite complex. In the case of a URL, where the reference to resolve is is a non hash fragment, the base URI is is the URI parts before (but including) the last slash.
(Note: JSON Schema defines that the value of an $id must be an absolute URI, without any fragments.)
So to answer your question specifically other.json should be identified as http://example.com/some/path/other.json.
You can see this in action if you try using the following schema in this online JSON Schema validator...
{
"$id": "http://example.com/blah/root.json",
"definitions": {
"A": {
"$id": "#foo"
},
"B": {
"$id": "other.json",
"definitions": {
"X": {
"$id": "#bar"
},
"Y": {
"$id": "t/inner.json"
}
}
},
"C": {
"$ref": "http://example.com/blah/other.json"
}
},
"properties":{
"a": { "$ref": "#/definitions/C" }
}
}
In the $ref for "C", if you remove /blah, the validator will complain it can no longer resolve the reference.
I'm trying to write a client to a large non Swagger-documented API and thought that writing the swagger.json
for it and using AutoRest would be a good way to accomplish that. The case is that this API wraps each operation's
response data into a larger object with control information, like this:
{
"resp_code": "SUCCESS",
"caller_ref": "2016111116233156169531",
"server_ref": "2016111116233189512798",
"data": {
"id": "idstring",
"name": "nameString",
"address": "addressString",
...
}
}
Where "data" in this case would be a "Client" definition for us. Is there a way to define the 200 OK response
schema and the definitions in the swagger.json file so that AutoRest would map this "data" to a Client class?
In fact the answer is quite trivial, all I had to do is to write the "responses" object of the swagger file like this:
"responses": {
"200": {
"description": "successful operation",
"schema": {
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/Client"
}
}
}
}
}
Besides creating the Client definition. AutoRest generates code that retrieves the "data" object, giving access to the Client within.
I want to define an object with a key and a value but can't figure out how to define it as a property in a swagger 2.0 definition. Frankly, I am not sure if this is even possible if one wants to be able to define strongly typed clients. However, I figure I'd ask to see if this is even possible/allowable.
Basically, I want to be able to store the following object:
{ "currencies":
{ "usd" : 1.10,
"eur" : 2.25
}
}
But I don't want usd, and eur to have to be defined in the schema. I can do the below but I don't want usd or eur to be predefined. I want it to accept any value for the keys of the object.
"Product": {
"properties": {
"currencies": {
"type": "currencyObj"
},
}
},
},
"currencyObj": {
"id": "currencyObj",
"properties": {
"eur": {
"type": "float"
},
"usd": {
"type": "float"
}
}
}
Swagger 2.0 allows you to define a string to type mapping, you need to use additionalProperties. Use following notation to define a map :
"currencyObj": {
"type": "object",
"additionalProperties": {
"type": "number"
}
}
I have a simple JSON object that can contain key/values for which the exact values are not known upfront. They depend on some server side process. How do I model this in Swagger?
An example of the JSON would be:
...
,message: "invalid length. Must be in between {min} and {max}"
,attributes: {
min: 0
,max: 6
}
...
Another example would be:
...
,message: "You must fill out this field as well because {field} has a value"
,attributes: {
field: "age"
}
...
The following solution will only work with Swagger 2.0.
Define the model as described like this:
{
"type": "object",
"properties": {
"message": {
"type": "string"
},
"attributes": {
"type": "object",
"additionalProperties": {}
}
}
}
This describes attributes as a map of properties, where the value can be anything (string, number, array and even an object).