OAI / OpenAPI-Specification

The OpenAPI Specification Repository
https://openapis.org
Apache License 2.0
28.62k stars 9.06k forks source link

Support deep objects for query parameters with deepObject style #1706

Open bajtos opened 5 years ago

bajtos commented 5 years ago

Background

Many applications expect deeply nested objects in input parameters, see the discussion in swagger-ui starting from this comment: https://github.com/swagger-api/swagger-ui/issues/4064#issuecomment-357417513 In LoopBack, we are running into this problem too, see https://github.com/strongloop/loopback-next/pull/1679.

Consider a filter parameter defined as follows:

parameters:
 filterParam:
   in: query
   name: filter
   schema:
     type: object
   style: deepObject
   explode: true
   description: Options for filtering the results
   required: false

Let's say the user wants to provide the following value, for example by entering a JSON into the text area rendered by swagger-ui:

{
  "name": "ivan",
  "birth-date": {
    "gte": "1970-01-01"
  }
}

At the moment, the OpenAPI Specification v3 does not describe how to encode such value in a query string. As a result, OpenAPI clients like swagger-ui don't know how to handle this input - see the discussion in https://github.com/swagger-api/swagger-js/issues/1385 for an example.

Proposal

The following query string should be created by swagger-js client for the input value shown above.

filter[name]=ivan&filter[birth-date][qte]=1970-01-01

The proposed serialization style is supported by https://www.npmjs.com/package/qs, which is used by http://expressjs.com as the default query parser, which means that a vast number of Node.js API servers are already expecting this serialization style.

I am not sure if there is any existing formal specification of this format, I am happy to look into that once my proposal gets considered as acceptable in principle.

Additional information

Existing issues that are touching a similar topic:

Two older comments from swagger-js that may be relevant:

https://github.com/swagger-api/swagger-js/pull/1140

Limitations: deepObject does not handle nested objects. The specification and swagger.io documentation does not provide an example for serializing deep objects. Flat objects will be serialized into the deepObject style just fine.

https://github.com/swagger-api/swagger-js/pull/1140#issuecomment-333017825

As for deepObject and nested objects - that was explicitly left out of the spec, and it's ok to just Not Support It™.

mbraz commented 1 year ago

waiting for "qs style" serialization feature

darrelmiller commented 1 year ago

@mbraz You are waiting for the feature in what tooling? Docs, testing, code generators? Here's how you could describe it in the specification.

parameters:
 filterParam:
   in: query
   name: filter
   schema:
     type: object
   style: deepObject
   x-deepObject-style: qs
   explode: true
   description: Options for filtering the results
   required: false

I just made that extension up. That's how we are going to move forward here.

The best way to get a feature into the specification is to propose an extension to a tooling creator, or PR a tool with support. Adoption of the the extension will be what demonstrates the value and allows us to bring the feature into the specification.

If you really don't want to go the extension route, you could do this as an alternative.

parameters:
 filterParam:
   in: query
   name: filter
   content:
     text/vnd.qs-serialization: {}
   description: Options for filtering the results
   required: false

In this case I invented a new text based media type for describing the contents of the filter value. Media types are not usually used for describing query parameter values, but it is technically allowed by OAS.

The important point here is that the real work is to go convince the tooling creators that this is an important feature to implement. The blocker is not the specification.

mbraz commented 1 year ago

Hi, wait in swagger to use in NestJS applications. I'll try text/vnd.qs-serialization...

Em dom., 5 de mar. de 2023 às 14:34, Darrel @.***> escreveu:

@mbraz https://github.com/mbraz You are waiting for the feature in what tooling? Docs, testing, code generators? Here's how you could describe it in the specification.

parameters: filterParam: in: query name: filter schema: type: object style: deepObject x-deepObject-style: qs explode: true description: Options for filtering the results required: false

I just made that extension up. That's how we are going to move forward here.

The best way to get a feature into the specification is to propose an extension to a tooling creator, or PR a tool with support. Adoption of the the extension will be what demonstrates the value and allows us to bring the feature into the specification.

If you really don't want to go the extension route, you could do this as an alternative.

parameters: filterParam: in: query name: filter content: text/vnd.qs-serialization: {} description: Options for filtering the results required: false

In this case I invented a new text based media type for describing the contents of the filter value. Media types are not usually used for describing query parameter values, but it is technically allowed by OAS.

— Reply to this email directly, view it on GitHub https://github.com/OAI/OpenAPI-Specification/issues/1706#issuecomment-1455153914, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA23VEFTQ4RDD3XPBOU4H5DW2TFDTANCNFSM4F257XBQ . You are receiving this because you were mentioned.Message ID: @.***>

handrews commented 2 months ago

I think the simplest way to allow folks to experiment with different approaches would be to implement #1502 (Support for arbitrary query strings). That would let folks define entirely custom serialization, perhaps based on media types as @darrelmiller suggests, without having to work around the spec's mechanisms for supporting more common serialization forms.

POMXARK commented 2 months ago

https://github.com/abbasudo/laravel-purity

This is extremely necessary! I can't convert to format query parameter

filters[is_publish][$contains]=true

Terrible. An outrageous flaw. And no one has undertaken to fix this with at least a third-party package

dafeder commented 2 months ago

@POMXARK let's keep it respectful, the maintainers don't owe you anything. You're welcome to submit a PR or make and share a third-party package if this is so important to you, we're all just doing our best here.

FWIW I'm not a JS developer but I would still strongly vote for standardizing around "qs style" as it's very intuitive and close enough to other serialization methods to work with in different languages. It should be recognized though that there is really no way to do nested query objects in a GET query string that will be straightforward to document.

handrews commented 2 months ago

@dafeder thanks for your comment!

It should be recognized though that there is really no way to do nested query objects in a GET query string that will be straightforward to document.

Yeah, this is why I'm pushing for #1502 in version 3.2 of the spec. It's not ideal, but it gets the OpenAPI spec details out of the way and lets folks do their own serialization for the entire query string, including by just setting the whole thing to content: {application/x-www-form-urlencoded: {...}} and serializing the way we do application/x-www-form-urlencoded bodies. Which would also allow creating 3rd-party extensions to handle alternate query string formats, which is not possible right now because there is no place in any Object where you could easily put such an extension.

dafeder commented 2 months ago

@handrews yes that makes a lot of sense, the problem is really more on the SwaggerUI side. As a spec I can see this being the right way to do it (and clarifying this will probably help Swagger handle it better).