How to define mutually exclusive query parameters in Swagger (OpenAPI)?
Asked Answered
R

4

54

I have a series of parameters in Swagger like this

                    "parameters": [
                    {
                        "name": "username",
                        "description": "Fetch username by username/email",
                        "required": false,
                        "type": "string",
                        "paramType": "query"
                    },
                    {
                        "name": "site",
                        "description": "Fetch username by site",
                        "required": false,
                        "type": "string",
                        "paramType": "query"
                    },
                    {
                        "name": "survey",
                        "description": "Fetch username by survey",
                        "required": false,
                        "type": "string",
                        "paramType": "query"
                    }
                ],

One parameter MUST be filled out but it doesn't matter which one, the others can be left blank. Is there a way to represent this in Swagger?

Rhodos answered 15/1, 2014 at 9:50 Comment(1)
Unfortunately not, it looks like this functionality just isn't availableRhodos
M
18

Unfortunately this isn't possible currently. "required" is just a boolean and there's no way to represent interdependencies between parameters.

Best you can do is make clear the requirements in the parameter descriptions and also put in a custom 400 Bad Request description along the same lines.

There's a bit of discussion at https://github.com/OAI/OpenAPI-Specification/issues/256 about possible ways of implementing this in the next version of the OpenAPI Specification.

Manzano answered 22/5, 2015 at 13:41 Comment(1)
OpenAPI 3.0 has a way to describe mutually exclusive parameters, see this answer.Osmunda
O
49

Mutually exclusive parameters are possible (sort of) in OpenAPI 3.x:

  • Define the mutually exclusive parameters as object properties, and use oneOf or maxProperties to limit the object to just 1 property.
  • Use the parameter serialization method style: form and explode: true, so that the object is serialized as ?propName=value.

An example using the minProperties and maxProperties constraints:

openapi: 3.0.0
...
paths:
  /foo:
    get:
      parameters:
        - in: query
          name: filter
          required: true
          style: form
          explode: true
          schema:
            type: object
            properties:
              username:
                type: string
              site:
                type: string
              survey:
                type: string
            minProperties: 1
            maxProperties: 1
            additionalProperties: false

Using oneOf:

      parameters:
        - in: query
          name: filter
          required: true
          style: form
          explode: true
          schema:
            type: object
            oneOf:
              - properties:
                  username:
                    type: string
                required: [username]
                additionalProperties: false
              - properties:
                  site:
                    type: string
                required: [site]
                additionalProperties: false
              - properties:
                  survey:
                    type: string
                required: [survey]
                additionalProperties: false

Another version using oneOf:

      parameters:
        - in: query
          name: filter
          required: true
          style: form
          explode: true
          schema:
            type: object
            properties:
              username:
                type: string
              site:
                type: string
              survey:
                type: string
            additionalProperties: false
            oneOf:
              - required: [username]
              - required: [site]
              - required: [survey]

Note that Swagger UI and Swagger Editor do not support the examples above yet (as of March 2018). This issue seems to cover the parameter rendering part.


There's also an open proposal in the OpenAPI Specification repository to support interdependencies between query parameters so maybe future versions of the Specification will have a better way to define such scenarios.

Osmunda answered 9/3, 2018 at 17:38 Comment(4)
Am I missing something obvious? As this doesn't seem to do any validation for me on aws' api gatewayTunnell
@Tunnell AWS API Gateway doesn't support oneOf and some other OpenAPI features.Osmunda
it seems like explode: true doesn't work, when you click on Try it out the whole object is seralized as the value for the name, instead of breaking out the properties of the object as individual parametersKeyes
@Keyes file a bug report with the tool that you used.Osmunda
M
18

Unfortunately this isn't possible currently. "required" is just a boolean and there's no way to represent interdependencies between parameters.

Best you can do is make clear the requirements in the parameter descriptions and also put in a custom 400 Bad Request description along the same lines.

There's a bit of discussion at https://github.com/OAI/OpenAPI-Specification/issues/256 about possible ways of implementing this in the next version of the OpenAPI Specification.

Manzano answered 22/5, 2015 at 13:41 Comment(1)
OpenAPI 3.0 has a way to describe mutually exclusive parameters, see this answer.Osmunda
A
6

What about changing your API design ? Currently you have one method, 3 parameters. If I understand well, user must always provide exactly one parameter, and two remaining ones must be unset.

For me, API would be more usable with three endpoints -like

/user/byName?name=
/user/bySite?name=
/user/bySurvey?name=
Ar answered 30/5, 2015 at 21:48 Comment(1)
Solves the technical issue but isn't very Restful.Bandwagon
B
3

An alternative is to pass in a filter type parameter with an enum, and a filter value with the value to use.

Example at: https://app.swaggerhub.com/api/craig_bayley/PublicAPIDemo/v1

It can be required or not, as you choose. However if one is required, they should both be.

Bandwagon answered 23/11, 2016 at 23:13 Comment(1)
do I understand correctly, that in this case your proposal, in this case, would produce API /users?name=name&filterType=[name|site|survey] ? I agree because this is more Restfull, because we have single resource, as it should be (still having clean and usable API).Ar

© 2022 - 2024 — McMap. All rights reserved.