Openapi-specification: Parameter of type "associative array"

Created on 27 May 2015  Â·  23Comments  Â·  Source: OAI/OpenAPI-Specification

Let's use the "pet store" application as example

Imagine that you can send multiple "find" requests in one. For that, you pass an array of associative arrays, which contain a list of integers

Text version:

criteria[0][status]: 1
criteria[0][tags]: 2,3
criteria[1][status]: 2
criteria[1][tags]: 4,5
POST /find HTTP/1.1
Host: petstore.com
Content-Type: application/x-www-form-urlencoded

criteria%5B0%5D%5Bstatus%5D=1&criteria%5B0%5D%5Btags%5D=2%2C3&criteria%5B1%5D%5Bstatus%5D=2&criteria%5B1%5D%5Btags%5D=4%2C5

How would you define that ?

I suggest the following syntax addition : adding a new property "indexType" to give the type of the keys in an array (default: integer, 0-based)

Example definition using this syntax

swagger: '2.0'
info:
  version: '1.0.0'
  title: Swagger Petstore (Simple)
  description: A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification
  termsOfService: http://helloreverb.com/terms/
  contact:
    name: Swagger API team
    email: [email protected]
    url: http://swagger.io
  license:
    name: MIT
    url: http://opensource.org/licenses/MIT
host: petstore.swagger.wordnik.com
basePath: /api
schemes:
  - http
consumes:
  - application/json
produces:
  - application/json
paths:
  /pets/find:
    get:
      description: Returns multiple search query results at the same time
      operationId: findPets
      produces:
        - application/json
        - application/xml
        - text/xml
        - text/html
      parameters:
        - name: criteria
          in: query
          description: search criteria
          required: true
          type: array
          items:
            type: array
            indexType: searchCriteria
            uniqueItems: true
            items:
              type: array
              items:
                type: integer
          collectionFormat: csv
      responses:
        '200':
          description: pet response
          schema:
            type: array
            items:
              type: array
              $ref: '#/definitions/pet'
        default:
          description: unexpected error
          schema:
            $ref: '#/definitions/errorModel'
definitions:
  searchCriteria:
    type: string
    enum:
    - tags
    - status
  pet:
    required:
      - id
      - name
    properties:
      id:
        type: integer
        format: int64
      name:
        type: string
      tag:
        type: string
  errorModel:
    required:
      - code
      - message
    properties:
      code:
        type: integer
        format: int32
      message:
        type: string
OpenAPI.Next Proposal Sub Issue

Most helpful comment

Technically, you can describe that today by naming the parameter date[gte] and setting the type to string.

All 23 comments

Hi there,

Any news on that? Associative arrays are all over the place in APIs (at least then ones I worked/work on)

I suggest using the simple "keys" parameter:

name: pop
description: population by country
type: array
keys:
    type: string
    description: country code (2 characters)
items:
    type: integer
    description: population (in thousands)

Do you think it is feasible to add it? For now I am using "x-keys" with the same format, but it won't display in the generated documentation (unless I'm mistaken)

Can you reference any public standard that defines such a format?

Can you reference any public common API that exposes that format?

Right now, the usage of this format seems esoteric.

On the contrary, can you firmly state that absolutely no API would have any use for associative arrays?

Just one example (because I do not know each and every API out there):

https://apidocs.mailchimp.com/api/2.0/lists/webhooks.php

Here the "actions" is a definite list that keeps growing. What if one day you could have any number of "actions" here, or even custom actions? The solution you propose would be to change the format of returned data so that it is not an associative array anymore, but an indexed array instead. Which would break existing code calling that API.

Instead, having an associative array here (which is nothing more than a generic object), would allow for a seamless transition.

Just my 2 cents. And authorizing a new property "keys" for "type: array" data does not seem that much esoteric to me. As long as something is constant (here it would be the items/values), it maskes sense to allow its declaration imho.

Someone else asked for it here : https://github.com/swagger-api/swagger-spec/issues/289

The given example is a list of data by country, with the country 2 letters code being the key (this is the example I quoted in my comment).

I can't say that, but I can say that we don't aim to accommodate for any kind of API out there, so just because there is a way to do it, that's not reason enough for us to support it.

As for the mailchimp API, that doesn't look anything like what the OP requested. It's just an array of objects which is already supported by the spec (though please correct me if I'm wrong).

As for defining a generic object, you can do that today too. It's ill-advised, and we don't encourage it, but you can. That's pretty much saying you don't want to document your API (in most cases, not all).

JSON Schema has something like this:

name: pop
description: population by country
type: object
patternProperties:
  '[A-Z]{2}':
    type: integer
    description: the population of the country indicated by the property name.

This syntax is not imported by Swagger, though. I guess if this would be supported, that would be the way to go.

That's indeed what I ended up using after some research. If Swagger does
not support it already, I'm confident they will soon!

Thank you Paulo!

Le lun. 14 sept. 2015 à 16:50, PaÅ­lo Ebermann [email protected] a
écrit :

JSON Schema has something like this:

name: popdescription: population by countrytype: objectpatternProperties:
'[A-Z]{2}':
type: integer
description: the population of the country indicated by the property name.

This syntax is not imported by Swagger, though. I guess if this would be
supported, that would be the way to go.

—
Reply to this email directly or view it on GitHub
https://github.com/swagger-api/swagger-spec/issues/380#issuecomment-140105023
.

The JSON API Spec actually has this for it's "field" query param.
/?fields[{TYPE}]={TYPE_FIELD1},{TYPE_FIELD2}&fields[{ANOTHER_TYPE}].....

http://jsonapi.org/format/#fetching-sparse-fieldsets

Rack is a quite common piece of software used in frameworks like Rails and Sinatra that has long parsed query parameters like array[]=1&array[]=2&array[]=3 into an array and hash[key]=value1&hash[another_key]=value2 into dict/hash types. Even then some parameters like hash[key_containing_array][] parse into a hash which contains an array.

This has been like this for a very long time. See https://github.com/rack/rack/blob/1.6.4/lib/rack/utils.rb#L111-L168 for their code.

I'd say there are tons of use cases out there like these where key and another_key are totally free-form. Probably less of those where hash is also completely free-form, but still existing.

:+1:

+1

Link to parent #565

+1

standard feature in all rails applications [1], also seems the only reasonable way to pass 1 or more! nested maps on through query strings. ie for essential for a GET request.

Also see "What Does normalize_params Do?" section for consice description how parsing is done.

[1] http://guides.rubyonrails.org/action_controller_overview.html#hash-and-array-parameters

Does anyone have a solution for this in the meantime? Obviously can't leave an endpoint undocumented.

I'm assuming something like this work work in the meantime?

{
            "name": "filters[tms_id]",
            "in": "query",
            "required": false,
            "type": "array",
            "items": {
              "type": "string"
            },
            "collectionFormat": "multi"
          }

I'm having a similar issue with array parameters. Does anyone have any suggestions how to describe an associative array in the query request such as:
http://example.com/api/rest/content?type=search&id=test&options[start]=20&options[limit]=10

I've come close with the following:

    - name: options
      in: query
      description: Additional options.
      required: false
      type: array
      items:
        type: string
      collectionFormat: multi

But that comes out as: http://example.com/api/rest/content?type=search&id=test&options=20&options=10

Hello,

stripe uses this for search by date API

something like

GET /charges?date[gte]=2016-01-01&date[lte]=2016-01-02

Is it related to your requirements?

@nemenemsrouge yes!, that's the same request pattern in the Stripe date API.

They are using date[gte] and date[lte] similar to how we are using options[offset] and options[limit] etc..

Is there any example of how to define that style date API GET request via the Swagger / OpenAPI spec?

I had a google but it appears the Stripe API docs are generated via a custom in-house tool ( https://www.quora.com/What-software-powers-the-Stripe-API-documentation )

@davidwhthomas I m sorry that I have no idea about how to do that...

Do you think using a "query" parameter and a type=object can do the job?

Maybe have to try...

Technically, you can describe that today by naming the parameter date[gte] and setting the type to string.

... but that does not scale to M fields by N operators. date[gte], date[gt], date[lte], date[lt], date[ne], then same for fields a, b, c. ... x, y, z, (We don't use notation such as this in our APis; I'm just noting that it is a stretch to enumerate all combinations.)

I didn't say it's a holistic solution, it can still be used to define explicit parameters if that's a requirement. I'm not familiar with Stripe's date API and it wasn't described as having varied inputs, only two. For two, it's definitely doable.

Thanks a lot. I test that today !

Is there any reason something like this won't work?
it works great when changing the parameter to body, it could just send the get param as

param1[0][name]=bla&param1[1][name]=foo

swagger: "2.0"
info:
  description: |
    This is a sample server Petstore server.
  version: "1.0.0"
  title: Swagger Petstore
  termsOfService: http://helloreverb.com/terms/
  contact:
    name: [email protected]
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
basePath: /v2
schemes:
  - http
paths:
  /test:
    get:
      summary: test
      description: test
      parameters:
        - name: param1
          in: query
          required: false
          description: test param1
          schema:
            type: array
            items:
              $ref: '#/definitions/bla'
      responses:
        200:
          description: OK
definitions:
  bla:
    type: object
    properties:
      name:
        type: string
        description: name of the object
Was this page helpful?
0 / 5 - 0 ratings

Related issues

mission-liao picture mission-liao  Â·  3Comments

rossi-jeff picture rossi-jeff  Â·  5Comments

domenique picture domenique  Â·  4Comments

aedart picture aedart  Â·  4Comments

ricellis picture ricellis  Â·  3Comments