Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write OpenAPI 3 (Swagger) specification for property name in `map` object?

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:

Swagger rendering of API

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?

like image 595
user2152081 Avatar asked Oct 03 '17 20:10

user2152081


People also ask

How do I create an OpenAPI Swagger spec?

How to generate OpenAPI from existing APIs. Head over to Swagger Inspector, and insert the end point of the resource you want to have documented. You can then navigate to the right panel from the History section of Swagger Inspector, and click "Create API definition" to create the OAS definition.

How does Swagger define map?

A dictionary (also known as a map, hashmap or associative array) is a set of key/value pairs. OpenAPI lets you define dictionaries where the keys are strings. To define a dictionary, use type: object and use the additionalProperties keyword to specify the type of values in key/value pairs.

What are the three primary section in a Swagger specification?

A Swagger version defines the overall structure of an API specification – what you can document and how you document it. Then, you need to specify the API info – title , description (optional), version (API version, not file revision or Swagger version).


1 Answers

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.

like image 72
Helen Avatar answered Oct 21 '22 12:10

Helen