Reputation: 1312
I need to document with Swagger an API that uses, both as input and output, maps of objects, indexed by string keys.
Example:
{
"a_property": {
"foo": {
"property_1": "a string 1",
"property_2": "a string 2"
},
"bar": {
"property_1": "a string 3",
"property_2": "a string 4"
}
}
}
"foo" and "bar" can be any string keys, but they should be unique among the set of keys.
I know that, with Swagger, I can define an array of objects, but this gives a different API since we then would have something as:
{
"a_property": [
{
"key": "foo"
"property_1": "a string 1",
"property_2": "a string 2"
},
{
"key": "bar"
"property_1": "a string 3",
"property_2": "a string 4"
}
]
}
I have read the 'Open API Specification' - 'Add support for Map data types #38' page. As far as I understand, it recommends to use additionalProperties, but it doesn't seem to answer my need (or it doesn't work with Swagger UI 2.1.4 that I use). Did I miss something?
So far I have found the following work-around (in Swagger JSON):
a_property: {
description: "This is a map that can contain several objects indexed by different keys.",
type: object,
properties: {
key: {
description: "map item",
type: "object",
properties: {
property_1: {
description: "first property",
type: string
},
property_2: {
description: "second property",
type: string
}
}
}
}
}
This almost does the job, but the reader has to understand that "key" can be any string, and can be repeated several times.
Is there a better way to achieve what I need?
Upvotes: 58
Views: 131822
Reputation: 7784
By using additionalProperties
:
definitions:
String-StringStringMap: # <-- use this as your result
type: object
additionalProperties:
$ref: "#/definitions/StringStringMap"
StringStringMap:
type: object
additionalProperties:
type: string
this results a 2 level map:
{
"additionalProp1": {
"additionalProp1": "string",
"additionalProp2": "string",
"additionalProp3": "string"
},
"additionalProp2": {
"additionalProp1": "string",
"additionalProp2": "string",
"additionalProp3": "string"
},
"additionalProp3": {
"additionalProp1": "string",
"additionalProp2": "string",
"additionalProp3": "string"
}
}
With same idea you can specify a 3 level map also.
Upvotes: 13
Reputation: 69
you can simply use type as object. When we are parsing data from frontend we have no such thing Map<Key,value>. we are just sending objects. Map is up to backend stuf. that is why I am asking to use object as the type. In objects we can send key value pairs. as the example given below
metaData:
type: object
example: {
"heading":"comfirmation email"
}
Upvotes: 1
Reputation: 5331
Using additionalProperties
is the proper way to describe hashmap with OpenAPI (fka. Swagger) Specification but Swagger UI do not render them for now.
The issue is tracked here https://github.com/swagger-api/swagger-ui/issues/1248
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:
MapItem:
properties:
firstname:
type: string
lastname:
type: string
Map:
description: a (key, MapItem) map. `default`is an example key
properties:
default:
$ref: '#/definitions/MapItem'
additionalProperties:
$ref: '#/definitions/MapItem'
This description does not modify API contract and improves documentation.
Upvotes: 65
Reputation: 167
If I understand it correctly, the basic problem is that there is no universally accepted JSON mapping for a Java Map, especially when the key is more complex than a string. I have seen that GSON takes one approach (treat the key as an object), whereas Jackson takes another (serialise the key to a string). The c# equivalent to a Map (a Dictionary) uses a third approach (treating each entry as a key-value object in its own right with properties called "Key" and "Value"). As Swagger tries to be agnostic to language and serialiser, this puts it in an impossible position.
Upvotes: 5