Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 23 additions & 20 deletions src/oas.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in other places we have used "serialization and parsing" or "parsing and serialization." Do you think "deserialization" is a better term here? Is there a distinction between that and "parsing"? I have no idea what the answer is, I either copied "parsing" or picked it without much thought, so I'm open to changing it as long as we're consistent.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I searched the document and found that "deserialize" was used more often than "parse". I've standardized on the former in my implementation (after waffling a few times) as I think the symmetry makes more sense. Also I think "parse" is a little more vague -- you parse a string for any number of reasons, but what we're really doing here when we parse a parameter string is deserializing it into the json document model so we can then validate it against a json schema, or pass it to the user application in a format closer to its final form.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I searched the document and found that "deserialize" was used more often than "parse".

I doublechecked this assertion and it's false. We talk a lot about "parsing an OAD", and that's definitely the correct language there, but we say both "parse a parameter" and "deserialize a parameter".

I think I still prefer "deserialize" for its extra specificity though, when it is applicable -- an OAD is parsed to interpret its rules, and parts of an HTTP message are deserialized to be applied against the OAD rules.

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.

Expand Down Expand Up @@ -819,8 +819,8 @@ In these cases, implementations MUST pass values through unchanged rather than a
| ---- | :----: | ---- |
| <a name="parameter-style"></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). |
| <a name="parameter-explode"></a>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`. |
| <a name="parameter-allow-reserved"></a>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. |
| <a name="parameter-schema"></a>schema | [Schema Object](#schema-object) | The schema defining the type used for the parameter. |
| <a name="parameter-allow-reserved"></a>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`). |
| <a name="parameter-schema"></a>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.

Expand Down Expand Up @@ -923,15 +923,15 @@ 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 | <span style="white-space: nowrap;">color=</span> | <span style="white-space: nowrap;">color=blue</span> | <span style="white-space: nowrap;">color=blue,black,brown</span> | <span style="white-space: nowrap;">color=R,100,G,200,B,150</span> |
| form | true | <span style="white-space: nowrap;">color=</span> | <span style="white-space: nowrap;">color=blue</span> | <span style="white-space: nowrap;">color=blue&color=black&color=brown</span> | <span style="white-space: nowrap;">R=100&G=200&B=150</span> |
| spaceDelimited | false | _n/a_ | _n/a_ | <span style="white-space: nowrap;">color=blue%20black%20brown</span> | <span style="white-space: nowrap;">color=R%20100%20G%20200%20B%20150</span> |
| 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_ | <span style="white-space: nowrap;">color=blue%7Cblack%7Cbrown</span> | <span style="white-space: nowrap;">color=R%7C100%7CG%7C200%7CB%7C150</span> |
| 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_ | <span style="white-space: nowrap;">color%5BR%5D=100&color%5BG%5D=200&color%5BB%5D=150</span> |
| cookie | false | <span style="white-space: nowrap;">color=</span> | <span style="white-space: nowrap;">color=blue</span> | <span style="white-space: nowrap;">color=blue,black,brown</span> | <span style="white-space: nowrap;">color=R,100,G,200,B,150</span> |
| cookie | true | <span style="white-space: nowrap;">color=</span> | <span style="white-space: nowrap;">color=blue</span> | <span style="white-space: nowrap;">color=blue; color=black; color=brown</span> | <span style="white-space: nowrap;">R=100; G=200; B=150</span> |
| 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

Expand Down Expand Up @@ -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.
Expand All @@ -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:
Expand Down Expand Up @@ -4908,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 §3.2](https://www.rfc-editor.org/rfc/rfc6570#section-3.2) ) 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.
Expand Down
42 changes: 29 additions & 13 deletions src/schemas/validation/schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -439,6 +435,8 @@ $defs:
const: path
then:
properties:
name:
pattern: '^[^{}]+$'
style:
default: simple
enum:
Expand All @@ -447,6 +445,11 @@ $defs:
- simple
required:
const: true
explode:
default: false
allowReserved:
type: boolean
default: false
required:
- required

Expand All @@ -460,6 +463,8 @@ $defs:
style:
default: simple
const: simple
explode:
default: false

styles-for-query:
if:
Expand All @@ -475,6 +480,10 @@ $defs:
- spaceDelimited
- pipeDelimited
- deepObject
allowReserved:
type: boolean
default: false
$ref: '#/$defs/explode-for-form'

styles-for-cookie:
if:
Expand All @@ -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

Expand Down Expand Up @@ -615,6 +635,7 @@ $defs:
properties:
allowReserved:
default: false
$ref: '#/$defs/explode-for-form'
explode:
properties:
style:
Expand All @@ -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:
Expand Down Expand Up @@ -808,9 +828,6 @@ $defs:
explode:
default: false
type: boolean
allowReserved:
default: false
type: boolean
allOf:
- $ref: '#/$defs/examples'
- $ref: '#/$defs/specification-extensions'
Expand Down Expand Up @@ -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:
Expand Down
12 changes: 12 additions & 0 deletions tests/schema/fail/header-object-allowReserved.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
openapi: 3.3.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
12 changes: 12 additions & 0 deletions tests/schema/fail/parameter-object-cookie-allowReserved.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
openapi: 3.3.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: {}
11 changes: 11 additions & 0 deletions tests/schema/fail/parameter-object-header-allowReserved.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
openapi: 3.3.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: {}
3 changes: 1 addition & 2 deletions tests/schema/pass/header-object-examples.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ components:
type: string
pattern: ^"
Reference:
$ref: '#/components/schemas/ETag'
$ref: '#/components/headers/ETag'
Style:
schema:
type: array
style: simple
explode: true
allowReserved: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
openapi: 3.3.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: {}
4 changes: 4 additions & 0 deletions tests/schema/pass/parameter-object-examples.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ paths:
in: header
description: token to be passed as a header
required: true
explode: false
schema:
type: array
items:
Expand All @@ -19,6 +20,7 @@ paths:
in: path
description: username to fetch
required: true
explode: false
schema:
type: string
- name: id
Expand Down Expand Up @@ -55,10 +57,12 @@ paths:
- in: cookie
name: my_cookie1
style: form
explode: true
schema: {}
- in: cookie
name: my_cookie2
style: cookie
explode: false
schema: {}
/user:
parameters:
Expand Down
12 changes: 12 additions & 0 deletions tests/schema/pass/parameter-object-path-allowReserved.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
openapi: 3.3.0
info:
title: api
version: 1.0.0
components:
parameters:
path:
name: my-path
in: path
required: true
allowReserved: false
schema: {}
11 changes: 11 additions & 0 deletions tests/schema/pass/parameter-object-query-allowReserved.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
openapi: 3.3.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: {}
Loading