diff --git a/src/oas.md b/src/oas.md
index 2b839b4554..5148de6065 100644
--- a/src/oas.md
+++ b/src/oas.md
@@ -769,14 +769,14 @@ See [Appendix E](#appendix-e-percent-encoding-and-form-media-types) for a detail
There are five 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`; MUST NOT appear in the same operation (or in the operation's path-item) as an `in: "querystring"` parameter.
+* query - Parameters that are appended to the URL with the `?` character (or for subsequent query parameters, with the `&` character); MUST NOT appear in the same operation (or in the operation's path-item) as an `in: "querystring"` parameter.
* querystring - A parameter that treats the entire URL query string as a value which MUST be specified using the `content` field, most often with media type `application/x-www-form-urlencoded` using [Encoding Objects](#encoding-object) in the same way as with request bodies of that media type; MUST NOT appear more than once, and MUST NOT appear in the same operation (or in the operation's path-item) as any `in: "query"` parameters.
* header - Custom headers that are expected as part of the request. Note that [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#section-5.1) 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.
@@ -819,8 +819,8 @@ In these cases, implementations MUST pass values through unchanged rather than a
| ---- | :----: | ---- |
| 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"` (for compatibility reasons; note that `style: "cookie"` SHOULD be used with `in: "cookie"`; see [Appendix D](#appendix-d-serializing-headers-and-cookies) for details). |
| 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, or when [`style`](#parameter-style) is `"deepObject"`, this field has no effect. When `style` is `"form"` or `"cookie"`, the default value is `true`. For all other styles, the default value is `false`. |
-| 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 by the rules of the `in` destination or media type, or are [not allowed in the path by this specification](#path-templating); see [URL Percent-Encoding](#url-percent-encoding) for details. The default value is `false`. This field only applies to `in` and `style` values that automatically percent-encode. |
-| schema | [Schema Object](#schema-object) | The schema defining the type used for the parameter. |
+| 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 by the rules of the `in` destination or media type, or are [not allowed in the path by this specification](#path-templating); see [URL Percent-Encoding](#url-percent-encoding) for details. The default value is `false`. This field only applies to `in` and `style` values that automatically percent-encode (that is: `in: path`, `in: query`, and `in: cookie` with `style: form`). |
+| schema | [Schema Object](#schema-object) | The schema defining the type and other constraints used for the parameter. |
See also [Appendix C: Using RFC6570-Based Serialization](#appendix-c-using-rfc6570-based-serialization) for additional guidance.
@@ -923,19 +923,19 @@ The following table shows serialized examples, as would be shown with the `seria
| 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 | _n/a_ | _n/a_ | _n/a_ | _n/a_ | color%5BR%5D=100&color%5BG%5D=200&color%5BB%5D=150 |
-| cookie | false | color= | color=blue | color=blue,black,brown | color=R,100,G,200,B,150 |
-| cookie | true | color= | color=blue | color=blue; color=black; color=brown | R=100; G=200; B=150 |
+| deepObject | _n/a_ | _n/a_ | _n/a_ | _n/a_ | color%5BR%5D=100&color%5BG%5D=200&color%5BB%5D=150 |
+| cookie | false | color= | color=blue | color=blue,black,brown | color=R,100,G,200,B,150 |
+| cookie | true | color= | color=blue | color=blue; color=black; color=brown | R=100; G=200; B=150 |
#### Extending Support for Querystring Formats
-Many frameworks define query string syntax for complex values, such as appending array indices to parameter names or indicating multiple levels of of nested objects, which go well beyond the capabilities of the `deepObject` style.
+Many frameworks define query string syntax for complex values, such as appending array indices to parameter names or indicating multiple levels of nested objects, which go well beyond the capabilities of the `deepObject` style.
As these are not standards, and often contradict each other, the OAS does not attempt to support them directly.
Two avenues are available for supporting such formats with `in: "querystring"`:
@@ -1070,7 +1070,7 @@ examples:
dataValue:
page: 4
pageSize: 50
- serializeValue: page=4&pageSize=50
+ serializedValue: page=4&pageSize=50
```
A complex parameter using `content` to define serialization, with multiple levels and types of examples shown to make the example usage options clear — note that `dataValue` is the same at both levels and does not need to be shown in both places in normal usage, but `serializedValue` is different:
@@ -1091,15 +1091,17 @@ content:
long:
type: number
examples:
- dataValue:
- lat: 10
- long: 60
- serializedValue: '{"lat":10,"long":60}'
+ 'New York':
+ dataValue:
+ lat: 40.6
+ long: -73.9
+ serializedValue: '{"lat":40.6,"long":-73.9}'
examples:
- dataValue:
- lat: 10
- long: 60
- serializedValue: coordinates=%7B%22lat%22%3A10%2C%22long%22%3A60%7D
+ 'New York':
+ dataValue:
+ lat: 40.6
+ long: -73.9
+ serializedValue: coordinates=%7B%22lat%22%3A40.6%2C%22long%22%3A-73.9%7D
```
A querystring parameter using regular form encoding, but managed with a Media Type Object.
@@ -1108,6 +1110,7 @@ Examples are shown at both the media type and parameter level to emphasize that,
```yaml
in: querystring
+name: metadata
content:
application/x-www-form-urlencoded:
schema:
@@ -2383,7 +2386,7 @@ The `serializedValue` and `externalValue` fields both MUST show the serialized f
For Media Type Objects, this is a document of the appropriate media type, with any Encoding Object effects applied.
For Parameter and Header Objects using `schema` and `style` rather than a Media Type Object, see [Style Examples](#style-examples) for what constitutes a serialized value.
-##### Criteria for `serializedExample`
+##### Criteria for `serializedValue`
A serialization can be represented as a valid Unicode string in `serializedValue` if any of the following are true of the serialization:
@@ -2858,7 +2861,7 @@ components:
In an HTTP message, the serialized example would look like:
```http
-Set-Cookie: lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GM
+Set-Cookie: lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT
Set-Cookie: foo=bar; Expires=Wed, 09 Jun 2021 10:18:14 GMT
Set-Cookie: urlSafeData=Hello%2C%20world%21
```
@@ -4449,8 +4452,7 @@ application/xml:
- Some text
- unit: cubits
value: 42
- null
- ]
+ - null
externalValue: ./examples/OneTwoThree.xml
```
@@ -4909,7 +4911,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.
@@ -4971,6 +4973,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 05e5704fe1..2f40e4b399 100644
--- a/src/schemas/validation/schema.yaml
+++ b/src/schemas/validation/schema.yaml
@@ -421,15 +421,11 @@ $defs:
type: string
explode:
type: boolean
- allowReserved:
- default: false
- type: boolean
allOf:
- $ref: '#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-path'
- $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:
@@ -439,6 +435,8 @@ $defs:
const: path
then:
properties:
+ name:
+ pattern: '^[^{}]+$'
style:
default: simple
enum:
@@ -447,6 +445,11 @@ $defs:
- simple
required:
const: true
+ explode:
+ default: false
+ allowReserved:
+ type: boolean
+ default: false
required:
- required
@@ -460,6 +463,8 @@ $defs:
style:
default: simple
const: simple
+ explode:
+ default: false
styles-for-query:
if:
@@ -475,6 +480,10 @@ $defs:
- spaceDelimited
- pipeDelimited
- deepObject
+ allowReserved:
+ type: boolean
+ default: false
+ $ref: '#/$defs/explode-for-form'
styles-for-cookie:
if:
@@ -488,6 +497,17 @@ $defs:
enum:
- form
- cookie
+ explode:
+ default: true
+ if:
+ properties:
+ style:
+ const: form
+ then:
+ properties:
+ allowReserved:
+ type: boolean
+ default: false
unevaluatedProperties: false
@@ -615,6 +635,7 @@ $defs:
properties:
allowReserved:
default: false
+ $ref: '#/$defs/explode-for-form'
explode:
properties:
style:
@@ -625,9 +646,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:
@@ -808,9 +828,6 @@ $defs:
explode:
default: false
type: boolean
- allowReserved:
- default: false
- type: boolean
allOf:
- $ref: '#/$defs/examples'
- $ref: '#/$defs/specification-extensions'
@@ -1118,13 +1135,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..8c448704a2
--- /dev/null
+++ b/tests/schema/fail/header-object-allowReserved.yaml
@@ -0,0 +1,12 @@
+openapi: 3.2.0
+info:
+ title: allowReserved only permitted with in and style values that percent-encode
+ 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-allowReserved.yaml b/tests/schema/fail/parameter-object-cookie-allowReserved.yaml
new file mode 100644
index 0000000000..09327beae5
--- /dev/null
+++ b/tests/schema/fail/parameter-object-cookie-allowReserved.yaml
@@ -0,0 +1,12 @@
+openapi: 3.2.0
+info:
+ title: allowReserved only permitted with in and style values that percent-encode
+ version: 1.0.0
+components:
+ parameters:
+ my_cookie:
+ name: my_cookie
+ in: cookie
+ style: cookie
+ allowReserved: true
+ 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..6b0a83d016
--- /dev/null
+++ b/tests/schema/fail/parameter-object-header-allowReserved.yaml
@@ -0,0 +1,11 @@
+openapi: 3.2.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/pass/header-object-examples.yaml b/tests/schema/pass/header-object-examples.yaml
index 4122c75c61..d0487663cd 100644
--- a/tests/schema/pass/header-object-examples.yaml
+++ b/tests/schema/pass/header-object-examples.yaml
@@ -23,4 +23,3 @@ components:
type: array
style: simple
explode: true
- allowReserved: true
\ No newline at end of file
diff --git a/tests/schema/pass/parameter-object-cookie-form-allowReserved.yaml b/tests/schema/pass/parameter-object-cookie-form-allowReserved.yaml
new file mode 100644
index 0000000000..ce5c5f58d7
--- /dev/null
+++ b/tests/schema/pass/parameter-object-cookie-form-allowReserved.yaml
@@ -0,0 +1,18 @@
+openapi: 3.2.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/pass/parameter-object-examples.yaml b/tests/schema/pass/parameter-object-examples.yaml
index 8a3db655ba..51e917362f 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
@@ -55,10 +57,12 @@ paths:
- in: cookie
name: my_cookie1
style: form
+ explode: false
schema: {}
- in: cookie
name: my_cookie2
style: cookie
+ explode: true
schema: {}
/user:
parameters:
diff --git a/tests/schema/pass/parameter-object-path-allowReserved.yaml b/tests/schema/pass/parameter-object-path-allowReserved.yaml
new file mode 100644
index 0000000000..5d394d901f
--- /dev/null
+++ b/tests/schema/pass/parameter-object-path-allowReserved.yaml
@@ -0,0 +1,12 @@
+openapi: 3.2.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/parameter-object-query-allowReserved.yaml b/tests/schema/pass/parameter-object-query-allowReserved.yaml
new file mode 100644
index 0000000000..237ece10eb
--- /dev/null
+++ b/tests/schema/pass/parameter-object-query-allowReserved.yaml
@@ -0,0 +1,11 @@
+openapi: 3.2.0
+info:
+ title: allowReserved only permitted with in and style values that percent-encode
+ 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..823eac7d94
--- /dev/null
+++ b/tests/schema/pass/style-defaults.yaml
@@ -0,0 +1,105 @@
+openapi: 3.2.0
+info:
+ title: various permutations of parameter objects, with non-required values left to their defaults
+ version: 1.0.0
+components:
+ mediaTypes:
+ 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
+ parameters:
+ 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: {}
+ cookie_cookie:
+ x-comment: "expecting defaults: required=false, deprecated=false, explode=true"
+ name: cookie_cookie
+ in: cookie
+ style: cookie
+ schema: {}