Skip to content

Commit 39448ef

Browse files
authored
Merge pull request #3818 from handrews/rfc6570-304
Appendix on RFC6570-derived behavior + `allowReserved` (3.0.4)
2 parents 95910fc + 8c3b071 commit 39448ef

File tree

1 file changed

+245
-2
lines changed

1 file changed

+245
-2
lines changed

versions/3.0.4.md

+245-2
Original file line numberDiff line numberDiff line change
@@ -1073,11 +1073,13 @@ Field Name | Type | Description
10731073
---|:---:|---
10741074
<a name="parameterStyle"></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`.
10751075
<a name="parameterExplode"></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 this property has no effect. When [`style`](#parameterStyle) is `form`, the default value is `true`. For all other styles, the default value is `false`.
1076-
<a name="parameterAllowReserved"></a>allowReserved | `boolean` | Determines whether the parameter value SHOULD allow reserved characters, as defined by [RFC3986](https://tools.ietf.org/html/rfc3986#section-2.2) `:/?#[]@!$&'()*+,;=` to be included without percent-encoding. This property only applies to parameters with an `in` value of `query`. The default value is `false`.
1076+
<a name="parameterAllowReserved"></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#autoid-20), which allows [RFC3986's reserved character set](https://datatracker.ietf.org/doc/html/rfc3986#autoid-13), 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#autoid-24) (`[`, `]`, `#`), or have a special meaning in `application/x-www-form-urlencoded` (`-`, `&`, `+`); see Appendices [C](#usingRFC6570Implementations) and [E](#percentEncodingAndFormMediaTypes) for details. This property only applies to parameters with an `in` value of `query`. The default value is `false`.
10771077
<a name="parameterSchema"></a>schema | [Schema Object](#schemaObject) \| [Reference Object](#referenceObject) | The schema defining the type used for the parameter.
10781078
<a name="parameterExample"></a>example | Any | Example of the parameter's potential value; see [Working With Examples](#working-with-examples).
10791079
<a name="parameterExamples"></a>examples | Map[ `string`, [Example Object](#exampleObject) \| [Reference Object](#referenceObject)] | Examples of the parameter's potential value; see [Working With Examples](#working-with-examples).
10801080

1081+
See also [Appendix C: Using RFC6570 Implementations](#usingRFC6570Implementations) for additional guidance.
1082+
10811083
###### Fixed Fields and considerations for use with `content`
10821084

10831085
For more complex scenarios, the [`content`](#parameterContent) property can define the media type and schema of the parameter, as well as give examples of its use.
@@ -1624,10 +1626,12 @@ Field Name | Type | Description
16241626
<a name="encodingHeaders"></a>headers | Map[`string`, [Header Object](#headerObject) \| [Reference Object](#referenceObject)] | A map allowing additional information to be provided as headers, for example `Content-Disposition`. `Content-Type` is described separately and SHALL be ignored in this section. This property SHALL be ignored if the request body media type is not a `multipart`.
16251627
<a name="encodingStyle"></a>style | `string` | Describes how a specific property value will be serialized depending on its type. See [Parameter Object](#parameterObject) for details on the [`style`](#parameterStyle) property. The behavior follows the same values as `query` parameters, including default values. This property SHALL be ignored if the request body media type is not `application/x-www-form-urlencoded`.
16261628
<a name="encodingExplode"></a>explode | `boolean` | When this is true, property 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 properties this property has no effect. When [`style`](#encodingStyle) is `form`, the default value is `true`. For all other styles, the default value is `false`. This property SHALL be ignored if the request body media type is not `application/x-www-form-urlencoded`.
1627-
<a name="encodingAllowReserved"></a>allowReserved | `boolean` | Determines whether the parameter value SHOULD allow reserved characters, as defined by [RFC3986](https://tools.ietf.org/html/rfc3986#section-2.2) `:/?#[]@!$&'()*+,;=` to be included without percent-encoding. The default value is `false`. This property SHALL be ignored if the request body media type is not `application/x-www-form-urlencoded`.
1629+
<a name="encodingAllowReserved"></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#autoid-20), which allows [RFC3986's reserved character set](https://datatracker.ietf.org/doc/html/rfc3986#autoid-13), 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#autoid-24) (`[`, `]`, `#`), or have a special meaning in `application/x-www-form-urlencoded` (`-`, `&`, `+`); see Appendices [C](#usingRFC6570Implementations) and [E](#percentEncodingAndFormMediaTypes) for details. This property only applies to parameters with an `in` value of `query`. The default value is `false`.
16281630

16291631
This object MAY be extended with [Specification Extensions](#specificationExtensions).
16301632

1633+
See also [Appendix C: Using RFC6570 Implementations](#usingRFC6570Implementations) for additional guidance.
1634+
16311635
##### Encoding Object Example
16321636

16331637
`multipart/form-data` allows for binary parts:
@@ -3696,4 +3700,243 @@ Version | Date | Notes
36963700

36973701
## <a name="usingRFC6570Implementations"></a>Appendix C: Using RFC6570 Implementations
36983702

3703+
Serialization is defined in terms of RFC6570 URI Templates in two scenarios:
3704+
3705+
Object | Condition
3706+
------ | ---------
3707+
[Parameter Object](#parameterObject) | When `schema` is present
3708+
[Encoding Object](#encodingObject) | When encoding for `application/x-www-form-urlencoded` and any of `style`, `explode`, or `allowReserved` are used
3709+
3710+
Implementations of this specification MAY use an implementation of RFC6570 to perform variable expansion, however, some caveats apply.
3711+
3712+
Note that when using `style: form` RFC6570 expansion to produce an `application/x-www-form-urlencoded` HTTP message body, it is necessary to remove the `?` prefix that is produced to satisfy the URI query string syntax.
3713+
3714+
Note also that not all RFC6570 implementations support all four levels of operators, all of which are needed to fully support the OpenAPI Specification's usage.
3715+
Using an implementation with a lower level of support will require additional manual construction of URI Templates to work around the limitations.
3716+
3717+
### Equivalences Between Fields and RFC6570 Operators
3718+
3719+
Certain field values translate to RFC6570 operators (or lack thereof):
3720+
3721+
field | value | equivalent
3722+
----- | ----- | ----------
3723+
style | simple | _n/a_
3724+
style | matrix | `;` prefix operator
3725+
style | label | `.` prefix operator
3726+
style | form | `?` prefix operator
3727+
allowReserved | `false` | _n/a_
3728+
allowReserved | `true` | `+` prefix operator
3729+
explode | `false` | _n/a_
3730+
explode | `true` | `*` modifier suffix
3731+
3732+
Multiple `style: form` parameters are equivalent to a single RFC6570 [variable list](https://www.rfc-editor.org/rfc/rfc6570#section-2.2) using the `?` prefix operator:
3733+
3734+
```YAML
3735+
parameters:
3736+
- name: foo
3737+
in: query
3738+
schema:
3739+
type: object
3740+
explode: true
3741+
- name: bar
3742+
in: query
3743+
schema:
3744+
type: string
3745+
```
3746+
3747+
This example is equivalent to RFC6570's `{?foo*,bar}`, and ***NOT*** `{?foo*}{&bar}`, which is problematic because if `foo` is not defined, the result will be an invalid URI.
3748+
The `&` prefix operator has no equivalent in the Parameter Object.
3749+
3750+
Note that RFC6570 does not specify behavior for compound values beyond the single level addressed by `explode`. The results of using objects or arrays where no behavior is clearly specified for them is implementation-defined.
3751+
3752+
### Non-RFC6570 Field Values and Combinations
3753+
3754+
Configurations with no direct RFC6570 equivalent SHOULD also be handled according to RFC6570.
3755+
Implementations MAY create a properly delimited URI Template with variables for individual names and values using RFC6570 regular or reserved expansion (based on `allowReserved`).
3756+
3757+
This includes:
3758+
* the styles `pipeDelimited`, `spaceDelimited`, and `deepObject`, which have no equivalents at all
3759+
* the combination of the style `form` with `allowReserved: true`, which is not allowed because only one prefix operator can be used at a time
3760+
* any parameter name that is not a legal RFC6570 variable name
3761+
3762+
The Parameter Object's `name` field has a much more permissive syntax than [RFC6570 variable name syntax](https://www.rfc-editor.org/rfc/rfc6570#section-2.3).
3763+
A parameter name that includes characters outside of the allowed RFC6570 variable character set MUST be percent-encoded before it can be used in a URI Template.
3764+
3765+
### Examples
3766+
3767+
Let's say we want to use the following data in a form query string, where `formulas` is exploded, and `words` is not:
3768+
3769+
```YAML
3770+
formulas:
3771+
a: x+y
3772+
b: x/y
3773+
c: x^y
3774+
words:
3775+
- math
3776+
- is
3777+
- fun
3778+
```
3779+
3780+
#### RFC6570-Equivalent Expansion
3781+
3782+
This array of parameter objects uses regular `style: form` expansion, fully supported by RFC6570:
3783+
3784+
```YAML
3785+
parameters:
3786+
- name: formulas
3787+
in: query
3788+
schema:
3789+
type: object
3790+
additionalProperties:
3791+
type: string
3792+
explode: true
3793+
- name: words
3794+
in: query
3795+
schema:
3796+
type: array
3797+
items:
3798+
type: string
3799+
```
3800+
3801+
This translates to the following URI Template:
3802+
3803+
```urlencoded
3804+
{?formulas*,words}
3805+
```
3806+
3807+
when expanded with the data given earlier, we get:
3808+
3809+
```urlencoded
3810+
?a=x%2By&b=x%2Fy&c=x%5Ey&words=math,is,fun
3811+
```
3812+
3813+
#### Expansion With Non-RFC6570-Supported Options
3814+
3815+
But now let's say that (for some reason), we really want that `/` in the `b` formula to show up as-is in the query string, and we want our words to be space-separated like in a written phrase.
3816+
To do that, we'll add `allowReserved: true` to `formulas`, and change to `style: spaceDelimited` for `words`:
3817+
3818+
```YAML
3819+
parameters:
3820+
- name: formulas
3821+
in: query
3822+
schema:
3823+
type: object
3824+
additionalProperties:
3825+
type: string
3826+
explode: true
3827+
allowReserved: true
3828+
- name: words
3829+
in: query
3830+
style: spaceDelimited
3831+
schema:
3832+
type: array
3833+
items:
3834+
type: string
3835+
```
3836+
3837+
We can't combine the `?` and `+` RFC6570 prefixes, and there's no way with RFC6570 to replace the `,` separator with a space character.
3838+
So we need to restructure the data to fit a manually constructed URI Template that passes all of the pieces through the right sort of expansion.
3839+
3840+
Here is one such template, using a made-up convention of `words.0` for the first entry in the words value, `words.1` for the second.
3841+
3842+
```urlencoded
3843+
?a={+a}&b={+b}&c={+c}&words={words.0} {words.1} {words.2}
3844+
```
3845+
3846+
RFC6570 [mentions](https://www.rfc-editor.org/rfc/rfc6570.html#section-2.4.2) the use of `.` "to indicate name hierarchy in substructures," but does not define any specific naming convention or behavior for it.
3847+
Since the `.` usage is not automatic, we'll need to construct an appropriate input structure for this new template.
3848+
3849+
We'll also need to pre-process the values for `formulas` because while `/` and most other reserved characters are allowed in the query string by RFC3986, `[`, `]`, and `#` [are not](https://datatracker.ietf.org/doc/html/rfc3986#appendix-A), and `&`, `=`, and `+` all have [special behavior](https://www.rfc-editor.org/rfc/rfc1866#section-8.2.1) in the `application/x-www-form-urlencoded` format, which is what we are using in the query string.
3850+
3851+
Setting `allowReserved: true` does _not_ make reserved characters that are not allowed in URIs allowed, it just allows them to be _passed through expansion unchanged._
3852+
Therefore, any tooling still needs to percent-encode those characters because reserved expansion will not do it, but it _will_ leave the percent-encoded triples unchanged.
3853+
See also [Appendix E](#to indicate name hierarchy in substructures) for further guidance on percent-encoding and form media types, including guidance on handling the delimiter characters for `spaceDelimited`, `pipeDelimited`, and `deepObject` in parameter names and values.
3854+
3855+
So here is our data structure that arranges the names and values to suit the template above, where values for `formulas` have `[]#&=+` pre-percent encoded (although only `+` appears in this example):
3856+
3857+
```YAML
3858+
a: x%2By
3859+
b: x/y
3860+
c: x^y
3861+
words.0: math
3862+
words.1: is
3863+
words.2: fun
3864+
```
3865+
3866+
Expanding our manually assembled template with our restructured data yields the following query string:
3867+
3868+
```urlencoded
3869+
?a=x%2By&b=x/y&c=x%5Ey&words=math%20is%20fun
3870+
```
3871+
The `/` and the pre-percent-encoded `%2B` have been left alone, but the disallowed `^` character (inside a value) and space characters (in the template but outside of the expanded variables) were percent-encoded.
3872+
3873+
#### Undefined Values and Manual URI Template Construction
3874+
3875+
Care must be taken when manually constructing templates to handle the values that [RFC6570 considers to be _undefined_](https://datatracker.ietf.org/doc/html/rfc6570#section-2.3) correctly:
3876+
3877+
```YAML
3878+
formulas: {}
3879+
words:
3880+
- hello
3881+
- world
3882+
```
3883+
3884+
Using this data with our original RFC6570-friendly URI Template, `{?formulas*,words}`, produces the following:
3885+
3886+
3887+
```urlencoded
3888+
?words=hello,world
3889+
```
3890+
3891+
This means that the manually constructed URI Template and restructured data need to leave out the `formulas` object entirely so that the `words` parameter is the first and only parameter in the query string.
3892+
3893+
Restructured data:
3894+
3895+
```YAML
3896+
words.0: hello
3897+
words.1: world
3898+
```
3899+
3900+
Manually constructed URI Template:
3901+
3902+
```urlencoded
3903+
?words={words.0} {words.1}
3904+
```
3905+
3906+
Result:
3907+
3908+
```urlencoded
3909+
?words=hello%20world
3910+
```
3911+
3912+
#### Illegal Variable Names as Parameter Names
3913+
In this example, the heart emoji is not legal in URI Template names (or URIs):
3914+
3915+
```YAML
3916+
parameters:
3917+
- name: ❤️
3918+
in: query
3919+
schema:
3920+
type: string
3921+
```
3922+
3923+
We can't just pass `❤️: love!` to an RFC6570 implementation.
3924+
Instead, we have to pre-percent-encode the name (which is a six-octet UTF-8 sequence) in both the data and the URI Template:
3925+
3926+
```YAML
3927+
"%E2%9D%A4%EF%B8%8F": love!
3928+
```
3929+
3930+
```urlencoded
3931+
{?%E2%9D%A4%EF%B8%8F}
3932+
```
3933+
3934+
This will expand to the result:
3935+
3936+
```urlencoded
3937+
?%E2%9D%A4%EF%B8%8F=love%21
3938+
```
3939+
36993940
## <a name="serializingHeadersAndCookies"></a>Appendix D: Serializing Headers and Cookies
3941+
3942+
## <a name="percentEncodingAndFormMediaTypes"></a>Appendix E: Percent-Encoding and Form Media Types

0 commit comments

Comments
 (0)