Delmo
Delmo

Reputation: 2276

How to define a mixed-type parameter using OpenAPI specification

I am following the OpenAPI (swagger) specification to define my API endpoints. This is an excerpt of an endpoint definition to get user's data:

"paths": {
  "/users/{id}": {
    "parameters": [
      {
        "name": "id",
        "in": "path",
        "description": "The user ID on which the operation will be executed.",
        "required": true,
        "type": "integer",
        "format": "int32",
      }
    ]
  }
}

But I want to use /users/me to get the data of logged in user (because at some point the user ID is unknown for logged user). As you can see me is a string, not an integer so I could not find a way to mix types in parameter definition according to OpenAPI specification.

Is there any way or workaround to do that? Should I define another endpoint /users/me and duplicate the /users/{id} definition to satisfy this need?

Upvotes: 3

Views: 1421

Answers (2)

Sanket Berde
Sanket Berde

Reputation: 6895

Simplest Solution will be to breakup this into two api's if you're not interested in multiplexing the same api.

eg.

/users/{id}
/current_user

The /current_user path won't even need any parameters as the authentication scheme you choose to implement would suffice.

Upvotes: 1

Ted Epstein
Ted Epstein

Reputation: 2889

I think there are two possible ways to do this:

  1. As you suggested, you can define a second endpoint at /users/me, without any path parameters. Swagger should allow this, because the the URI strings are distinct. The users/me segment doesn't match an endpoint expecting an integer value; nor does an integer match the fixed string me.
  2. You could also define a single path, with the {id} parameter typed as a string, with a pattern constraint that allows 'me' or an integer.

Here's what the second option would look like:

{
  "paths": {
    "/users/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "description": "The user ID on which the operation will be executed.",
          "required": true,
          "type": "string",
          "pattern": "^[-+]?[1-9]\\d*$|^[Mm][Ee]$"
        }
      ]
    }
  }
}

Notes:

  • The regular expression allows an optional leading + or - sign, followed by an integer value. If you don't need signed integers, you can remove the [-+]? expression.
  • This allows an arbitrary integer, without any range restriction, and with leading zeroes disallowed. Restricting this to the int32 range is considerably messier, but possible if you need to do it.
  • Note the escaped backslash for \d (decimal numeral). JSON strings require this.
  • The regex also allows me as an alternative to the integer, using any combination of upper and lower case.

As for whether to use the first or second option, it really depends on your API and your code. If the API contract is exactly the same, syntactically, the second option has the advantage of only requiring one path object, therefore only one handler in your code.

If the rules are different, e.g. the /users/me variant requires an API key or user token to be passed in the header, then the first option might be cleaner.

Upvotes: 3

Related Questions