Skip to content

Commit c097759

Browse files
authored
Merge pull request #4745 from handrews/mixed2
v3.2: (Split and smaller!) Support ordered multipart including streaming
2 parents fb8af87 + a514ba3 commit c097759

File tree

5 files changed

+86
-17
lines changed

5 files changed

+86
-17
lines changed

src/oas.md

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,18 @@ Some examples of sequential media types (including some that are not IANA-regist
103103
application/json-seq
104104
application/geo+json-seq
105105
text/event-stream
106+
multipart/mixed
106107
```
107108

108109
In the first three above, the repeating structure is any [JSON value](https://tools.ietf.org/html/rfc8259#section-3).
109-
The fourth repeats `application/geo+json`-structured values, while the last repeats a custom text format related to Server-Sent Events.
110+
The fourth repeats `application/geo+json`-structured values, while `text/event-stream` repeats a custom text format related to Server-Sent Events.
111+
The final media type listed above, `multipart/mixed`, provides an ordered list of documents of any media type, and is sometimes streamed.
112+
Note that while `multipart` formats technically allow a preamble and an epilogue, the RFC directs that they are to be ignored, making them effectively comments, and this specification does not model them.
110113

111114
Implementations MUST support mapping sequential media types into the JSON Schema data model by treating them as if the values were in an array in the same order.
112115

113116
See [Complete vs Streaming Content](#complete-vs-streaming-content) for more information on handling sequential media types in a streaming context, including special considerations for `text/event-stream` content.
117+
For `multipart` types, see also [Encoding By Position](#encoding-by-position).
114118

115119
#### Media Type Registry
116120

@@ -1278,7 +1282,9 @@ See [Working With Examples](#working-with-examples) for further guidance regardi
12781282
| <a name="media-type-item-schema"></a>itemSchema | [Schema Object](#schema-object) | A schema describing each item within a [sequential media type](#sequential-media-types). |
12791283
| <a name="media-type-example"></a>example | Any | Example of the media type; see [Working With Examples](#working-with-examples). |
12801284
| <a name="media-type-examples"></a>examples | Map[ `string`, [Example Object](#example-object) \| [Reference Object](#reference-object)] | Examples of the media type; see [Working With Examples](#working-with-examples). |
1281-
| <a name="media-type-encoding"></a>encoding | Map[`string`, [Encoding Object](#encoding-object)] | A map between a property name and its encoding information, as defined under [Encoding Usage and Restrictions](#encoding-usage-and-restrictions). The `encoding` field SHALL only apply when the media type is `multipart` or `application/x-www-form-urlencoded`. If no Encoding Object is provided for a property, the behavior is determined by the default values documented for the Encoding Object. |
1285+
| <a name="media-type-encoding"></a>encoding | Map[`string`, [Encoding Object](#encoding-object)] | A map between a property name and its encoding information, as defined under [Encoding By Name](#encoding-by-name). The `encoding` field SHALL only apply when the media type is `multipart` or `application/x-www-form-urlencoded`. If no Encoding Object is provided for a property, the behavior is determined by the default values documented for the Encoding Object. This field MUST NOT be present if `prefixEncoding` or `itemEncoding` are present. |
1286+
| <a name="media-type-prefix-encoding"></a>prefixEncoding | [[Encoding Object](#encoding-object)] | An array of positional encoding information, as defined under [Encoding By Position](#encoding-by-position). The `prefixEncoding` field SHALL only apply when the media type is `multipart`. If no Encoding Object is provided for a property, the behavior is determined by the default values documented for the Encoding Object. This field MUST NOT be present if `encoding` is present. |
1287+
| <a name="media-type-item-encoding"></a>itemEncoding | [Encoding Object](#encoding-object) | A single Encoding Object that provides encoding information for multiple array items, as defined under [Encoding By Position](#encoding-by-position). The `itemEncoding` field SHALL only apply when the media type is `multipart`. If no Encoding Object is provided for a property, the behavior is determined by the default values documented for the Encoding Object. This field MUST NOT be present if `encoding` is present. |
12821288

12831289
This object MAY be extended with [Specification Extensions](#specification-extensions).
12841290

@@ -1298,7 +1304,8 @@ For this use case, `maxLength` MAY be implemented outside of regular JSON Schema
12981304

12991305
###### Streaming Sequential Media Types
13001306

1301-
The `itemSchema` field is provided to support streaming use cases for sequential media types.
1307+
The `itemSchema` field is provided to support streaming use cases for sequential media types, with `itemEncoding` as a corresponding encoding mechanism for streaming [positional `multipart` media types](#encoding-by-position).
1308+
13021309
Unlike `schema`, which is applied to the complete content (treated as an array as described in the [sequential media types](#sequential-media-types) section), `itemSchema` MUST be applied to each item in the stream independently, which supports processing each item as it is read from the stream.
13031310

13041311
Both `schema` and `itemSchema` MAY be used in the same Media Type Object.
@@ -1334,30 +1341,48 @@ properties:
13341341

13351342
##### Encoding Usage and Restrictions
13361343

1337-
The `encoding` field defines how to map each [Encoding Object](#encoding-object) to a specific value in the data.
1344+
These encoding fields define how to map each [Encoding Object](#encoding object) to a specific value in the data.
1345+
Each field has its own set of media types with which it can be used; for all other media types all three fields SHALL be ignored.
13381346

1339-
To use the `encoding` field, a `schema` MUST exist, and the `encoding` field's keys MUST exist in the schema as properties.
1340-
Array properties MUST be handled by applying the given Encoding Object to one part per array item, each with the same `name`, as is recommended by [[?RFC7578]] [Section 4.3](https://www.rfc-editor.org/rfc/rfc7578.html#section-4.3) for supplying multiple values per form field.
1341-
For all other value types for both top-level non-array properties and for values, including array values, within a top-level array, the Encoding Object MUST be applied to the entire value.
1347+
###### Encoding By Name
13421348

13431349
The behavior of the `encoding` field is designed to support web forms, and is therefore only defined for media types structured as name-value pairs that allow repeat values, most notably `application/x-www-form-urlencoded` and `multipart/form-data`.
1350+
1351+
To use the `encoding` field, each key under the field MUST exist as a property; `encoding` entries with no corresponding property SHALL be ignored.
1352+
Array properties MUST be handled by applying the given Encoding Object to produce one encoded value per array item, each with the same `name`, as is recommended by [[!RFC7578]] [Section 4.3](https://www.rfc-editor.org/rfc/rfc7578.html#section-4.3) for supplying multiple values per form field.
1353+
For all other value types for both top-level non-array properties and for values, including array values, within a top-level array, the Encoding Object MUST be applied to the entire value.
13441354
The order of these name-value pairs in the target media type is implementation-defined.
13451355

13461356
For `application/x-www-form-urlencoded`, the encoding keys MUST map to parameter names, with the values produced according to the rules of the [Encoding Object](#encoding-object).
13471357
See [Encoding the `x-www-form-urlencoded` Media Type](#encoding-the-x-www-form-urlencoded-media-type) for guidance and examples, both with and without the `encoding` field.
13481358

1349-
For `multipart`, the encoding keys MUST map to the [`name` parameter](https://www.rfc-editor.org/rfc/rfc7578#section-4.2) of the `Content-Disposition: form-data` header of each part, as is defined for `multipart/form-data` in [[?RFC7578]].
1350-
See [[?RFC7578]] [Section 5](https://www.rfc-editor.org/rfc/rfc7578.html#section-5) for guidance regarding non-ASCII part names.
1351-
1352-
Other `multipart` media types are not directly supported as they do not define a mechanism for part names.
1353-
However, the usage of a `name` [`Content-Disposition` parameter](https://www.iana.org/assignments/cont-disp/cont-disp.xhtml#cont-disp-2) is defined for the `form-data` [`Content-Disposition` value](https://www.iana.org/assignments/cont-disp/cont-disp.xhtml#cont-disp-1), which is not restricted to `multipart/form-data`.
1354-
Implementations MAY choose to support the a `Conent-Disposition` of `form-data` with a `name` parameter in other `multipart` media types in order to use the `encoding` field with them, but this usage is unlikely to be supported by generic `multipart` implementations.
1359+
For `multipart`, the encoding keys MUST map to the [`name` parameter](https://www.rfc-editor.org/rfc/rfc7578#section-4.2) of the `Content-Disposition: form-data` header of each part, as is defined for `multipart/form-data` in [[!RFC7578]].
1360+
See [[!RFC7578]] [Section 5](https://www.rfc-editor.org/rfc/rfc7578.html#section-5) for guidance regarding non-ASCII part names.
13551361

13561362
See [Encoding `multipart` Media Types](#encoding-multipart-media-types) for further guidance and examples, both with and without the `encoding` field.
13571363

1364+
###### Encoding By Position
1365+
1366+
Most `multipart` media types, including `multipart/mixed` which defines the underlying rules for parsing all `multipart` types, do not have named parts.
1367+
Data for these media types are modeled as an array, with one item per part, in order.
1368+
1369+
To use the `prefixEncoding` and/or `itemEncoding` fields, either `itemSchema` or an array `schema` MUST be present.
1370+
These fields are analogous to the `prefixItems` and `items` JSON Schema keywords, with `prefixEncoding` (if present) providing an array of Encoding Objects that are each applied to the value at the same position in the data array, and `itemEncoding` applying its single Encoding Object to all remaining items in the array.
1371+
As with `prefixItems`, it is _not_ an error if the instance array is shorter than the `prefixEncoding` array; the additional Encoding Objects SHALL be ignored.
1372+
1373+
The `itemEncoding` field can also be used with `itemSchema` to support streaming `multipart` content.
1374+
1375+
###### Additional Encoding Approaches
1376+
1377+
The `prefixEncoding` field can be used with any `multipart` content to require a fixed part order.
1378+
This includes `multipart/form-data`, for which the Encoding Object's `headers` field MUST be used to provide the `Content-Disposition` and part name, as no property names exist to provide the names automatically.
1379+
1380+
Prior versions of this specification advised using the [`name` parameter](https://www.rfc-editor.org/rfc/rfc7578#section-4.2) of the `Content-Disposition: form-data` header of each part with `multipart` media types other than `multipart/form-data` in order to work around the limitations of the `encoding` field.
1381+
Implementations MAY choose to support this workaround, but as this usage is not common, implementations of non-`form-data` `multipart` media types are unlikely to support it.
1382+
13581383
##### Media Type Examples
13591384

1360-
For form-related media type examples, see the [Encoding Object](#encoding-object).
1385+
For form-related and `multipart` media type examples, see the [Encoding Object](#encoding-object).
13611386

13621387
###### JSON
13631388

@@ -1673,8 +1698,9 @@ These fields MAY be used either with or without the RFC6570-style serialization
16731698
This object MAY be extended with [Specification Extensions](#specification-extensions).
16741699

16751700
The default values for `contentType` are as follows, where an _n/a_ in the `contentEncoding` column means that the presence or value of `contentEncoding` is irrelevant.
1676-
This table is based on the value to which the Encoding Object is being applied, which as defined under [Encoding Usage and Restrictions](#encoding-usage-and-restrictions) is the array item for properties of type `"array"`, and the entire value for all other types.
1677-
Therefore the `array` row in this table applies only to array values inside of a top-level array.
1701+
This table is based on the value to which the Encoding Object is being applied as defined under [Encoding Usage and Restrictions](#encoding-usage-and-restrictions).
1702+
Note that in the case of [Encoding By Name](#encoding-by-name), this value is the array item for properties of type `"array"`, and the entire value for all other types.
1703+
Therefore the `array` row in this table applies only to array values inside of a top-level array when encoding by name.
16781704

16791705
| `type` | `contentEncoding` | Default `contentType` |
16801706
| ---- | ---- | ---- |

src/schemas/validation/schema.yaml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,9 +539,20 @@ $defs:
539539
type: object
540540
additionalProperties:
541541
$ref: '#/$defs/encoding'
542+
prefixEncoding:
543+
type: array
544+
items:
545+
$ref: '#/$defs/encoding'
546+
itemEncoding:
547+
$ref: '#/$defs/encoding'
542548
allOf:
543-
- $ref: '#/$defs/specification-extensions'
544549
- $ref: '#/$defs/examples'
550+
- $ref: '#/$defs/specification-extensions'
551+
- dependentSchemas:
552+
encoding:
553+
properties:
554+
prefixEncoding: false
555+
itemEncoding: false
545556
unevaluatedProperties: false
546557

547558
media-type-or-reference:
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
openapi: 3.2.0
2+
info:
3+
title: API
4+
version: 1.0.0
5+
components:
6+
requestBodies:
7+
encoding-with-itemEncoding-not-allowed:
8+
content:
9+
multipart/mixed:
10+
encoding: {}
11+
itemEncoding: {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
openapi: 3.2.0
2+
info:
3+
title: API
4+
version: 1.0.0
5+
components:
6+
requestBodies:
7+
encoding-with-prefixEncoding-not-allowed:
8+
content:
9+
multipart/mixed:
10+
encoding: {}
11+
prefixEncoding: []

tests/schema/pass/media-type-examples.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,13 @@ paths:
161161
prefixEncoding:
162162
- {}
163163
itemEncoding: {}
164+
multipart/related:
165+
schema:
166+
type: array
167+
itemEncoding:
168+
contentType: text/plain
169+
prefixEncoding:
170+
- headers:
171+
Content-Location:
172+
schema:
173+
type: string

0 commit comments

Comments
 (0)