diff --git a/src/oas.md b/src/oas.md
index b81e67fe8b..1b35b81252 100644
--- a/src/oas.md
+++ b/src/oas.md
@@ -1134,13 +1134,13 @@ See [Appendix E](#appendix-e-percent-encoding-and-form-media-types) for a detail
There are four possible parameter locations specified by the `in` field:
* path - Used together with [Path Templating](#path-templating), where the parameter value is actually part of the operation's URL. This does not include the host or base path of the API. For example, in `/items/{itemId}`, the path parameter is `itemId`.
-* query - Parameters that are appended to the URL. For example, in `/items?id=###`, the query parameter is `id`.
+* query - Parameters that are appended to the URL with the `?` character (or for subsequent query parameters, with the `&` character).
* header - Custom headers that are expected as part of the request. Note that [RFC7230](https://tools.ietf.org/html/rfc7230#section-3.2) states header names are case insensitive.
* cookie - Used to pass a specific cookie value to the API.
##### Fixed Fields
-The rules for serialization of the parameter are specified in one of two ways.
+The rules for serialization and deserialization of the parameter are specified in one of two ways.
Parameter Objects MUST include either a `content` field or a `schema` field, but not both.
See [Appendix B](#appendix-b-data-type-conversion) for a discussion of converting values of various types to string representations.
@@ -1177,7 +1177,7 @@ Serializing with `schema` is NOT RECOMMENDED for `in: "cookie"` parameters; see
| style | `string` | Describes how the parameter value will be serialized depending on the type of the parameter value. Default values (based on value of `in`): for `"query"` - `"form"`; for `"path"` - `"simple"`; for `"header"` - `"simple"`; for `"cookie"` - `"form"`. |
| explode | `boolean` | When this is true, parameter values of type `array` or `object` generate separate parameters for each value of the array or key-value pair of the map. For other types of parameters this field has no effect. When [`style`](#parameter-style) is `"form"`, the default value is `true`. For all other styles, the default value is `false`. Note that despite `false` being the default for `deepObject`, the combination of `false` with `deepObject` is undefined. |
| allowReserved | `boolean` | When this is true, parameter values are serialized using reserved expansion, as defined by [RFC6570](https://datatracker.ietf.org/doc/html/rfc6570#section-3.2.3), which allows [RFC3986's reserved character set](https://datatracker.ietf.org/doc/html/rfc3986#section-2.2), as well as percent-encoded triples, to pass through unchanged, while still percent-encoding all other disallowed characters (including `%` outside of percent-encoded triples). Applications are still responsible for percent-encoding reserved characters that are [not allowed in the query string](https://datatracker.ietf.org/doc/html/rfc3986#section-3.4) (`[`, `]`, `#`), or have a special meaning in `application/x-www-form-urlencoded` (`-`, `&`, `+`); see [URL Percent-Encoding](#url-percent-encoding) for details. This field only applies to parameters with an `in` value of `query`. The default value is `false`. |
-| schema | [Schema Object](#schema-object) | The schema defining the type used for the parameter. |
+| schema | [Schema Object](#schema-object) | The schema defining the type and other constraints used for the parameter. |
| example | Any | Example of the parameter's potential value; see [Working With Examples](#working-with-examples). |
| examples | Map[ `string`, [Example Object](#example-object) \| [Reference Object](#reference-object)] | Examples of the parameter's potential value; see [Working With Examples](#working-with-examples). |
@@ -1277,14 +1277,14 @@ The following table shows serialized examples, as would be shown with the `examp
| label | true | _empty_ | .blue | .blue.black.brown | .R=100.G=200.B=150 |
| simple | false | _empty_ | blue | blue,black,brown | R,100,G,200,B,150 |
| simple | true | _empty_ | blue | blue,black,brown | R=100,G=200,B=150 |
-| form | false | color= | color=blue | color=blue,black,brown | color=R,100,G,200,B,150 |
-| form | true | color= | color=blue | color=blue&color=black&color=brown | R=100&G=200&B=150 |
-| spaceDelimited | false | _n/a_ | _n/a_ | color=blue%20black%20brown | color=R%20100%20G%20200%20B%20150 |
+| form | false | color= | color=blue | color=blue,black,brown | color=R,100,G,200,B,150 |
+| form | true | color= | color=blue | color=blue&color=black&color=brown | R=100&G=200&B=150 |
+| spaceDelimited | false | _n/a_ | _n/a_ | color=blue%20black%20brown | color=R%20100%20G%20200%20B%20150 |
| spaceDelimited | true | _n/a_ | _n/a_ | _n/a_ | _n/a_ |
-| pipeDelimited | false | _n/a_ | _n/a_ | color=blue%7Cblack%7Cbrown | color=R%7C100%7CG%7C200%7CB%7C150 |
+| pipeDelimited | false | _n/a_ | _n/a_ | color=blue%7Cblack%7Cbrown | color=R%7C100%7CG%7C200%7CB%7C150 |
| pipeDelimited | true | _n/a_ | _n/a_ | _n/a_ | _n/a_ |
| deepObject | false | _n/a_ | _n/a_ | _n/a_ | _n/a_ |
-| deepObject | true | _n/a_ | _n/a_ | _n/a_ | color%5BR%5D=100&color%5BG%5D=200&color%5BB%5D=150 |
+| deepObject | true | _n/a_ | _n/a_ | _n/a_ | color%5BR%5D=100&color%5BG%5D=200&color%5BB%5D=150 |
##### Parameter Object Examples
@@ -4361,7 +4361,7 @@ parameters:
type: string
```
-This example is equivalent to RFC6570's `{?foo*,bar}`, and **NOT** `{?foo*}{&bar}`. The latter is problematic because if `foo` is not defined, the result will be an invalid URI.
+This example is equivalent to RFC6570's `{?foo*,bar}`, and **NOT** `{?foo*}{&bar}`. The latter is problematic because if `foo` is not defined (see [RFC6570 ยง2.3](https://www.rfc-editor.org/rfc/rfc6570#section-2.3) for details on what is considered undefined), the result will be an invalid URI.
The `&` prefix operator has no equivalent in the Parameter Object.
Note that RFC6570 does not specify behavior for compound values beyond the single level addressed by `explode`. The result of using objects or arrays where no behavior is clearly specified for them is implementation-defined.
@@ -4423,6 +4423,7 @@ parameters:
type: array
items:
type: string
+ explode: false
```
This translates to the following URI Template:
diff --git a/src/schemas/validation/schema.yaml b/src/schemas/validation/schema.yaml
index f4059cb1d3..565fe8545f 100644
--- a/src/schemas/validation/schema.yaml
+++ b/src/schemas/validation/schema.yaml
@@ -359,7 +359,6 @@ $defs:
- $ref: '#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-header'
- $ref: '#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-query'
- $ref: '#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-cookie'
- - $ref: '#/$defs/styles-for-form'
$defs:
styles-for-path:
@@ -369,6 +368,8 @@ $defs:
const: path
then:
properties:
+ name:
+ pattern: '^[^{}]+$'
style:
default: simple
enum:
@@ -377,6 +378,8 @@ $defs:
- simple
required:
const: true
+ explode:
+ default: false
required:
- required
@@ -390,6 +393,8 @@ $defs:
style:
default: simple
const: simple
+ explode:
+ default: false
styles-for-query:
if:
@@ -408,6 +413,7 @@ $defs:
allowReserved:
default: false
type: boolean
+ $ref: '#/$defs/explode-for-form'
styles-for-cookie:
if:
@@ -419,6 +425,7 @@ $defs:
style:
default: form
const: form
+ $ref: '#/$defs/explode-for-form'
$ref: '#/$defs/specification-extensions'
unevaluatedProperties: false
@@ -508,6 +515,7 @@ $defs:
properties:
allowReserved:
default: false
+ $ref: '#/$defs/explode-for-form'
explode:
properties:
style:
@@ -518,9 +526,8 @@ $defs:
properties:
style:
default: form
- allOf:
- - $ref: '#/$defs/specification-extensions'
- - $ref: '#/$defs/styles-for-form'
+ $ref: '#/$defs/explode-for-form'
+ $ref: '#/$defs/specification-extensions'
unevaluatedProperties: false
responses:
@@ -956,13 +963,12 @@ $defs:
additionalProperties:
type: string
- styles-for-form:
+ explode-for-form:
+ $comment: for encoding objects, and query and cookie parameters, style=form is the default
if:
properties:
style:
const: form
- required:
- - style
then:
properties:
explode:
diff --git a/tests/schema/fail/header-object-allowReserved.yaml b/tests/schema/fail/header-object-allowReserved.yaml
new file mode 100644
index 0000000000..0babaf22df
--- /dev/null
+++ b/tests/schema/fail/header-object-allowReserved.yaml
@@ -0,0 +1,12 @@
+openapi: 3.1.0
+info:
+ title: "allowReserved only permitted with in: query"
+ version: 1.0.0
+components:
+ headers:
+ Style:
+ schema:
+ type: array
+ style: simple
+ explode: true
+ allowReserved: true
diff --git a/tests/schema/fail/parameter-object-cookie-form-allowReserved.yaml b/tests/schema/fail/parameter-object-cookie-form-allowReserved.yaml
new file mode 100644
index 0000000000..ee88d3ac79
--- /dev/null
+++ b/tests/schema/fail/parameter-object-cookie-form-allowReserved.yaml
@@ -0,0 +1,18 @@
+openapi: 3.1.0
+info:
+ title: allowReserved only permitted with in and style values that percent-encode
+ version: 1.0.0
+components:
+ parameters:
+ style_form:
+ name: my_form_cookie
+ in: cookie
+ # default style is form, therefore allowReserved is allowed
+ allowReserved: true
+ schema: {}
+ style_cookie:
+ name: my_cookie_cookie
+ in: cookie
+ style: cookie
+ # no percent decoding for style=cookie, therefore allowReserved is not allowed
+ schema: {}
diff --git a/tests/schema/fail/parameter-object-header-allowReserved.yaml b/tests/schema/fail/parameter-object-header-allowReserved.yaml
new file mode 100644
index 0000000000..4b956a080d
--- /dev/null
+++ b/tests/schema/fail/parameter-object-header-allowReserved.yaml
@@ -0,0 +1,11 @@
+openapi: 3.1.0
+info:
+ title: allowReserved only permitted with in and style values that percent-encode
+ version: 1.0.0
+components:
+ parameters:
+ header:
+ name: my-header
+ in: header
+ allowReserved: false
+ schema: {}
diff --git a/tests/schema/fail/parameter-object-path-allowReserved.yaml b/tests/schema/fail/parameter-object-path-allowReserved.yaml
new file mode 100644
index 0000000000..09a5f94a86
--- /dev/null
+++ b/tests/schema/fail/parameter-object-path-allowReserved.yaml
@@ -0,0 +1,11 @@
+openapi: 3.1.0
+info:
+ title: "allowReserved only permitted with in: query"
+ version: 1.0.0
+components:
+ parameters:
+ path:
+ name: my-path
+ in: path
+ allowReserved: false
+ schema: {}
diff --git a/tests/schema/failparameter-object-path-allowReserved.yaml b/tests/schema/failparameter-object-path-allowReserved.yaml
new file mode 100644
index 0000000000..1d01ac62e0
--- /dev/null
+++ b/tests/schema/failparameter-object-path-allowReserved.yaml
@@ -0,0 +1,12 @@
+openapi: 3.1.0
+info:
+ title: api
+ version: 1.0.0
+components:
+ parameters:
+ path:
+ name: my-path
+ in: path
+ required: true
+ allowReserved: false
+ schema: {}
diff --git a/tests/schema/pass/header-object-examples.yaml b/tests/schema/pass/header-object-examples.yaml
index 7b91efbbae..305e598486 100644
--- a/tests/schema/pass/header-object-examples.yaml
+++ b/tests/schema/pass/header-object-examples.yaml
@@ -22,4 +22,4 @@ components:
schema:
type: array
style: simple
- explode: true
\ No newline at end of file
+ explode: true
diff --git a/tests/schema/pass/parameter-object-examples.yaml b/tests/schema/pass/parameter-object-examples.yaml
index fe6a13ea7c..30c7b29058 100644
--- a/tests/schema/pass/parameter-object-examples.yaml
+++ b/tests/schema/pass/parameter-object-examples.yaml
@@ -9,21 +9,23 @@ paths:
in: header
description: token to be passed as a header
required: true
+ explode: false
schema:
type: array
items:
type: integer
format: int64
style: simple
- - name: username
+ - name: usernames
in: path
- description: username to fetch
+ description: usernames to fetch
required: true
+ explode: false
schema:
- type: string
+ type: array
- name: id
in: query
- description: ID of the object to fetch
+ description: IDs of the object to fetch
required: false
schema:
type: array
@@ -51,4 +53,9 @@ paths:
lat:
type: number
long:
- type: number
\ No newline at end of file
+ type: number
+ - in: cookie
+ name: my_cookie1
+ style: form
+ explode: false
+ schema: {}
diff --git a/tests/schema/pass/parameter-object-query-allowReserved.yaml b/tests/schema/pass/parameter-object-query-allowReserved.yaml
new file mode 100644
index 0000000000..26f89ab781
--- /dev/null
+++ b/tests/schema/pass/parameter-object-query-allowReserved.yaml
@@ -0,0 +1,11 @@
+openapi: 3.1.0
+info:
+ title: "allowReserved only permitted with in: query"
+ version: 1.0.0
+components:
+ parameters:
+ my_query:
+ name: my_query
+ in: query
+ allowReserved: true
+ schema: {}
diff --git a/tests/schema/pass/style-defaults.yaml b/tests/schema/pass/style-defaults.yaml
new file mode 100644
index 0000000000..c3942bdc50
--- /dev/null
+++ b/tests/schema/pass/style-defaults.yaml
@@ -0,0 +1,102 @@
+openapi: 3.1.0
+info:
+ title: various permutations of parameter objects, with non-required values left to their defaults
+ version: 1.0.0
+components:
+ parameters:
+ encoding_object_defaults:
+ name: encoding_object_defaults
+ in: path
+ content:
+ encoding_object_defaults: # media type name
+ encoding:
+ no_styles: # property name
+ x-comment: "style, explode and allowReserved are not present, so contentType is used; no defaults expected as default contentType cannot be determined by the schema"
+ style_form:
+ x-comment: "expecting defaults: explode=true, allowReserved=false"
+ style: form
+ style_spaceDelimited:
+ x-comment: "expecting defaults: explode=false, allowReserved=false"
+ style: spaceDelimited
+ explode:
+ x-comment: "expecting defaults: style=form, allowReserved=false"
+ explode: false
+ allowReserved:
+ x-comment: "expecting default: style=form, explode=true"
+ allowReserved: true
+ path_media_type:
+ x-comment: "expecting defaults: deprecated=false"
+ name: path_media-type
+ in: path
+ required: true
+ content:
+ text/*:
+ schema: {}
+ path_simple:
+ x-comment: "expecting defaults: deprecated=false, style=simple, explode=false, allowReserved=false"
+ name: path_simple
+ in: path
+ required: true
+ schema: {}
+ path_matrix:
+ x-comment: "expecting defaults: deprecated=false, explode=false, allowReserved=false"
+ name: path_matrix
+ in: path
+ required: true
+ style: matrix
+ schema: {}
+ path_label:
+ x-comment: "expecting defaults: deprecated=false, explode=false, allowReserved=false"
+ name: path_label
+ in: path
+ required: true
+ style: label
+ schema: {}
+ query_media_type:
+ x-comment: "expecting defaults: required=false, deprecated=false, allowEmptyValue=false"
+ name: query_media_type
+ in: query
+ content:
+ text/*:
+ schema: {}
+ query_form:
+ x-comment: "expecting defaults: required=false, deprecated=false, allowEmptyValue=false, style=form, explode=true, allowReserved=false"
+ name: query_form
+ in: query
+ schema: {}
+ query_spaceDelimited:
+ x-comment: "expecting defaults: required=false, deprecated=false, allowEmptyValue=false, explode=false, allowReserved=false"
+ name: query_spaceDelimited
+ in: query
+ style: spaceDelimited
+ schema: {}
+ query_pipeDelimited:
+ x-comment: "expecting defaults: required=false, deprecated=false, allowEmptyValue=false, explode=false, allowReserved=false"
+ name: query_pipeDelimited
+ in: query
+ style: pipeDelimited
+ schema: {}
+ query_deepObject:
+ x-comment: "expecting defaults: required=false, deprecated=false, allowEmptyValue=false, allowReserved=false"
+ name: query_deepObject
+ in: query
+ style: deepObject
+ schema: {}
+ header:
+ x-comment: "expecting defaults: deprecated=false, style=simple, explode=false, allowReserved=false"
+ name: header
+ in: path
+ required: true
+ schema: {}
+ cookie_media_type:
+ x-comment: "expecting defaults: required=false, deprecated=false"
+ name: cookie_media_type
+ in: cookie
+ content:
+ text/*:
+ schema: {}
+ cookie_form:
+ x-comment: "expecting defaults: required=false, deprecated=false, style=form, explode=true, allowReserved=false"
+ name: cookie_form
+ in: cookie
+ schema: {}