Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arbitrary query parameter names? #2622

Closed
danieljacobs1 opened this issue Jun 17, 2021 · 9 comments
Closed

Arbitrary query parameter names? #2622

danieljacobs1 opened this issue Jun 17, 2021 · 9 comments

Comments

@danieljacobs1
Copy link

I'm pretty new to openapi, so apologies if this has been asked before. I haven't been able to find a similar question anywhere.

I'm working creating an openapi.yml for an existing API we have at my workplace.

For better or worse, the API supports arbitrary query parameter names. Values are always supplied. These pairs are interpreted as tag name/value pairs of particular resources (computational resources). Here are a few examples (with some name simplifications) of how the API can be invoked:

GET /resources?state=active&tagName1=tagValue1&tagName2=tagValue2

GET /resources?tagName6=tagValue6

GET /resources?state=active

Both the tagNameNs and tagValueN's are user-supplied and arbitrary, but have to conform to be "identifier names" (no spaces, alphanumeric, must not start with a digit).

The only query parameter with a fixed, known name is state.

Is there some way of expressing this notion in openapi?

I appreciate this is pretty unusual, and perhaps the description might be the only means to express this.

For reference here's a section of my openapi.yml file for this endpoint.

openapi: 3.0.0
info:
  title: Service
  description: Endpoints
  version: 1.0.0
paths:
  /resources:
    get:
      parameters:
        - in: query
          name: state
          schema:
            type: string
            enum:
              - active
              - inactive
        - in: query
         # TODO - how to describe tagNameN/tagValueN here?
      responses:
        '200':
          description: "All resources successfully obtained."

Any insights or advice appreciated.

Thanks in advance.

@MikeRalphson
Copy link
Member

I checked the issues for "dynamic parameter names" and came up with issues #1637 and #1054 which may be related? Can you let me know if you think there is some similarity and maybe we can coalesce the discussion here as you have expressed the issue in quite general terms.

@danieljacobs1
Copy link
Author

danieljacobs1 commented Jun 17, 2021

Thanks for the fast reply. I think I saw those earlier when I was searching around, but I wasn't sure.

It would be nice for confirmation, but I read #1637 as if they have an endpoint that can produce the query parameter names and would it be possible to generate a UI dynamically from its response.

And #1054 has the q as it's query parameter name and it feels a bit different.

For the case I'm asking about, I was imagining it might look like this:

openapi: 3.0.0
info:
  title: Service
  description: Endpoints
  version: 1.0.0
paths:
  /resources:
    get:
      parameters:
        - in: query
          name: state
          schema:
            type: string
            enum:
              - active
              - inactive
        - in: query
          metaVarName: tagName  # Mutually exclusive with 'name'
            schema:
              type: string
              regexp: [_a-zA-Z][_a-zA-Z0-9]*
          metaVarValue: tagValue
            schema:
              type: string
              regexp: [_a-zA-Z][_a-zA-Z0-9]*
      responses:
        '200':
          description: "All resources successfully obtained."

and it could generate a UI that allowed adding of arbitrary numbers of name/value pairs for tags.

It might be possible that one solution in openapi solves all three of the problems, but I'm not qualified to say.

@hkosova
Copy link
Contributor

hkosova commented Jun 18, 2021

@danieljacobs1 Free-form query parameters can be defined as a single parameter whose value is a dictionary and that uses style: form + explode: true (this is the default serialization style for query parameters). The parameter name can be arbitrary, it does not appear in the URL but may be used by code generators.

Both the tagNameNs and tagValueN's are user-supplied and arbitrary, but have to conform to be "identifier names" (no spaces, alphanumeric, must not start with a digit).

The name format can be defined in OAS 3.1 using patternProperties or propertyNames. Make sure to use the ^ and $ anchors in regexes because regexes are not implicitly anchored.

patternProperties example:

        - in: query
          name: tags  # Arbitrary name
          schema:
            type: object
            patternProperties:
              # Parameter names
              '^[A-Za-z][A-Za-z0-9]*$':
                # Parameter values
                type: string
                pattern: '^[A-Za-z][A-Za-z0-9]*$'
            additionalProperties: false
            example:
              tagName1: tagValue1
              tagName2: tagValue2

propertyNames example:

        - in: query
          name: tags  # Arbitrary name
          schema:
            type: object
            propertyNames:
              pattern: '^[A-Za-z][A-Za-z0-9]*$'  # Parameter names
            additionalProperties:     # Schema for parameter values
              type: string
              pattern: '^[A-Za-z][A-Za-z0-9]*$'
            example:
              tagName1: tagValue1
              tagName2: tagValue2

OAS 3.0 also supports free-form query parameters, but does not have a way to limit their names.

        - in: query
          name: tags  # Arbitrary name
          schema:
            type: object
            additionalProperties:  # Schema for parameter values
              type: string
              pattern: '^[A-Za-z][A-Za-z0-9]*$'
            example:
              tagName1: tagValue1
              tagName2: tagValue2

@danieljacobs1
Copy link
Author

Thanks @hkosova.

... can be defined as a single parameter whose value is a dictionary ...

Unfortunately, I'm not at liberty to change the API at the moment. The tag names have to be the query string parameter names as this is an existing API with many clients.

The dictionary value would be a good approach going forward for new endpoints.

@karenetheridge
Copy link
Member

The name format can be defined in OAS 3.1 using patternProperties or propertyNames

Isn't the schema for a query parameter describing the expected format of the query value, not its name? If not, where does one put the schema for the query value?

@hkosova
Copy link
Contributor

hkosova commented Jun 23, 2021

@karenetheridge

Isn't the schema for a query parameter describing the expected format of the query value, not its name?

Technically yes, but in this particular scenario the schema is exploded so that its properties become individual key/value params in the query string. So it may be 1 parameter (of type object) in the function call in the code - e.g. getResources(tags) - but multiple query parameters in the URL.

This is similar to request bodies containing form data, where top-level properties of the body schema correspond to individual form fields.

@hkosova
Copy link
Contributor

hkosova commented Jun 23, 2021

@danieljacobs1

... can be defined as a single parameter whose value is a dictionary ...

Unfortunately, I'm not at liberty to change the API at the moment. The tag names have to be the query string parameter names as this is an existing API with many clients.

Not sure I follow. Do you mean the function declarations in your server/client code? (E.g. in case you generate this code from OpenAPI or vice versa.)

Just to clarify - my example does produce the query string that you need. Here're how the OAS 3.0 version works in Swagger Editor (cannot try OAS 3.1 as it's not supported yet):

@danieljacobs1
Copy link
Author

Sorry for being so very slow getting back on this. @hkosova your screenshot looks exactly like what I was looking for. Thank you! I'll close this issue. Thanks again.

@Nikoolayy1
Copy link

Thanks! Great workaround for wildcard parameters.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants