From 8ae8aa9abfc72acc35506ec41b040c0a35ae46dd Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Wed, 16 Sep 2020 17:27:25 -0700 Subject: [PATCH 1/6] Fix, clarify, and simplify content type schemas This fixes #2349, which caught that an encoded PNG image is encoded into a text media type. In the process I realized some other errors, and simplified things. * HTTP `Content-Type` is always handled by OAS * Media Type Object key in most cases * Encoding object (possibly inferred from schema) in `multipart/form-data` * HTTP-level `Content-Encoding` is always handled by the OAS Header Object * JSON Schema "content*" is used for embedding one media type into another * the encoded resource is of media type `text/plain` * `"contentMediaType"` is the embedded media type after decoding * `"contentEncoding"` is how to encode/decode binary to/from text This removes any chance of `"contentMediaType"` conflicting with the Media Type Object key or with `contentType` in the Encoding Object, as they now always do different things. Likewise, the HTTP `Content-Encoding` header (with values like gzip, deflate, etc.) does different things than `"contentEncoding"` (which has values like base64, base64url, quoted-printable, etc.). The deprecated part header `Content-Transfer-Encoding` is likewise handled in the Encoding Object, but is probably never used. --- versions/3.1.0.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/versions/3.1.0.md b/versions/3.1.0.md index dbdecaa4ea..f094e15201 100644 --- a/versions/3.1.0.md +++ b/versions/3.1.0.md @@ -1433,10 +1433,7 @@ application/json: ##### Considerations for File Uploads -In contrast with the 2.0 specification, `file` input/output content in OpenAPI is described with the same semantics as any other schema type. In contrast with the 3.0 specification, such schemas use the `contentEncoding` JSON Schema keyword rather than the `format` keyword. This keyword supports all encodings defined in [RFC4648](https://tools.ietf.org/html/rfc4648), including "base64" and "base64url", as well as "quoted-printable" from [RFC2045](https://tools.ietf.org/html/rfc2045#section-6.7). - -JSON Schema also offers a `contentMediaType` keyword. However, when the media type is already specified by the -Media Type Object's key, or by the `contentType` field of an [Encoding Object](#encodingObject), the `contentMediaType` keyword SHALL be ignored if present. +In contrast with the 2.0 specification, `file` input/output content in OpenAPI is described with the same semantics as any other schema type. In contrast with the 3.0 specification, such schemas either omit the `type` (in place of `format: binary`), or use `contentMediaType` and `contentEncoding` with `type: string`. The `contentEncoding` keyword supports all encodings defined in [RFC4648](https://tools.ietf.org/html/rfc4648), including "base64" (which replaces `format: byte`) and "base64url", as well as "quoted-printable" from [RFC2045](https://tools.ietf.org/html/rfc2045#section-6.7). Examples: @@ -1458,12 +1455,15 @@ Binary content transferred with base64 encoding: ```yaml content: - image/png: + text/plain: schema: type: string + contentMediaType: image/png contentEncoding: base64 ``` +Note that the `Content-Type` is `text/plain`, since from an HTTP perspective, base64-encoded data is simply text. The `contentMediaType` and `contentEncoding` fields inform the application how to encode and decode the resource from and to its actual media type. + These examples apply to either input payloads of file uploads or response payloads. A `requestBody` for submitting a file in a `POST` operation may look like the following example: @@ -1496,10 +1496,11 @@ requestBody: # The property name 'file' will be used for all files. file: type: array - items: - contentMediaType: application/octet-stream + items: {} ``` +As seen in the section on `multipart/form-data` below, the empty schema for `items` indicates a media type of `application/octet-stream`. + ##### Support for x-www-form-urlencoded Request Bodies To submit content using form url encoding via [RFC1866](https://tools.ietf.org/html/rfc1866), the following @@ -1535,10 +1536,9 @@ When passing in `multipart` types, boundaries MAY be used to separate sections o * If the property is a primitive, or an array of primitive values, the default Content-Type is `text/plain` * If the property is complex, or an array of complex values, the default Content-Type is `application/json` -* If the property is a `type: string` with a `contentEncoding`, the default Content-Type is `application/octet-stream` -* If the JSON Schema keyword `contentMediaType` is used and no Encoding Object is present, then the Content-Type is that which is specified by `contentMediaType`, however if an Encoding Object is present, then `contentMediaType` SHALL be ignored +* If the property is a `type: string` with a `contentEncoding`, the default Content-Type is `text/plain`, and the media type of the embedded resource is specified in `contentMediaType` -As with non-multipart request or response bodies, when using `contentMediaType` to specify a binary Content-Type without also using `contentEncoding`, the JSON Schema `type` keyword is omitted. +Per the JSON Schema specification, `contentMediaType` without `contentEncoding` present is treated as if `contentEncoding: identity` were present. While useful for embedding text documents such as `text/html` into JSON strings, it is not useful for a `multipart/form-data` part, as it just causes the document to be treated as `text/plain` instead of its actual media type. Use the Encoding Object without `contentMediaType` if no `contentEncoding` is required. Examples: @@ -1557,15 +1557,17 @@ requestBody: type: object properties: {} profileImage: - # Content-Type with contentMediaType is the contentMediaType (image/png here) + # Content-Type for application-level encoded resource is `text/plain` + type: string contentMediaType: image/png + contentEncoding: base64 children: - # default Content-Type for arrays is based on the `inner` type (text/plain here) + # default Content-Type for arrays is based on the _inner_ type (`text/plain` here) type: array items: type: string addresses: - # default Content-Type for arrays is based on the `inner` type (object shown, so `application/json` in this example) + # default Content-Type for arrays is based on the _inner_ type (object shown, so `application/json` in this example) type: array items: type: object @@ -1581,7 +1583,7 @@ A single encoding definition applied to a single schema property. ##### Fixed Fields Field Name | Type | Description ---|:---:|--- -contentType | `string` | The Content-Type for encoding a specific property. Default value depends on the property type: when `type` is absent and `contentMediaType` is present - the value of `contentMediaType`; when both `type` and `contentMediaType` are absent - `application/octet-stream`; for `string` with a `contentEncoding` - `application/octet-string`; for other primitive types – `text/plain`; for `object` - `application/json`; for `array` – the default is defined based on the inner type. The value can be a specific media type (e.g. `application/json`), a wildcard media type (e.g. `image/*`), or a comma-separated list of the two types. +contentType | `string` | The Content-Type for encoding a specific property. Default value depends on the property type: when `type` is absent - `application/octet-stream`; for primitive types - `text/plain`; for `object` - `application/json`; when `type` is `string` and `contentEncoding` is present, the default Content-Type is `text/plain`, and the media type of the encoded resource is specified in `contentMediaType`; for `array` – the default is defined based on the inner type. The value can be a specific media type (e.g. `application/json`), a wildcard media type (e.g. `image/*`), or a comma-separated list of the two types. 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`. 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` or `multipart/form-data`. If a value is explicitly defined, then the value of [`contentType`](#encodingContentType) (implicit or explicit) SHALL be ignored. 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` or `multipart/form-data`. If a value is explicitly defined, then the value of [`contentType`](#encodingContentType) (implicit or explicit) SHALL be ignored. @@ -1594,7 +1596,7 @@ This object MAY be extended with [Specification Extensions](#specificationExtens ```yaml requestBody: content: - multipart/mixed: + multipart/form-data: schema: type: object properties: @@ -1611,9 +1613,7 @@ requestBody: description: metadata in XML format type: object properties: {} - profileImage: - type: string - contentMediaType: image/jpeg + profileImage: {} encoding: historyMetadata: # require XML Content-Type in utf-8 encoding From 7477f9b05f937e737e96db0b7da340d10f88a24a Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Thu, 21 Jan 2021 13:00:41 -0800 Subject: [PATCH 2/6] Fix Content-Type to indicate semantics ...rather than literal content format on the wire. --- versions/3.1.0.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/versions/3.1.0.md b/versions/3.1.0.md index f094e15201..5c8b644c94 100644 --- a/versions/3.1.0.md +++ b/versions/3.1.0.md @@ -1455,14 +1455,14 @@ Binary content transferred with base64 encoding: ```yaml content: - text/plain: + image/png: schema: type: string contentMediaType: image/png contentEncoding: base64 ``` -Note that the `Content-Type` is `text/plain`, since from an HTTP perspective, base64-encoded data is simply text. The `contentMediaType` and `contentEncoding` fields inform the application how to encode and decode the resource from and to its actual media type. +Note that the `Content-Type` remains `image/png`, describing the semantics of the payload. The JSON Schema `type` and `contentEncoding` fields explain that the payload is transferred as text. The JSON Scheam `contentMediaType` is technically redundant, but can be used by JSON Schema tools that may not be aware of the OpenAPI context. These examples apply to either input payloads of file uploads or response payloads. From 9321a4b6ba91da329062350ff197e6555f94c375 Mon Sep 17 00:00:00 2001 From: Darrel Date: Thu, 28 Jan 2021 12:38:12 -0500 Subject: [PATCH 3/6] Update 3.1.0.md Fixed a typo and changed a SHOULD to MAY. --- versions/3.1.0.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/versions/3.1.0.md b/versions/3.1.0.md index 5c8b644c94..d8e115f734 100644 --- a/versions/3.1.0.md +++ b/versions/3.1.0.md @@ -1437,7 +1437,7 @@ In contrast with the 2.0 specification, `file` input/output content in OpenAPI i Examples: -Content transferred in binary (octet-stream) SHOULD omit `schema`, as no JSON Schema type is suitable: +Content transferred in binary (octet-stream) MAY omit `schema`: ```yaml # a PNG image as a binary file: @@ -1462,7 +1462,7 @@ content: contentEncoding: base64 ``` -Note that the `Content-Type` remains `image/png`, describing the semantics of the payload. The JSON Schema `type` and `contentEncoding` fields explain that the payload is transferred as text. The JSON Scheam `contentMediaType` is technically redundant, but can be used by JSON Schema tools that may not be aware of the OpenAPI context. +Note that the `Content-Type` remains `image/png`, describing the semantics of the payload. The JSON Schema `type` and `contentEncoding` fields explain that the payload is transferred as text. The JSON Schema `contentMediaType` is technically redundant, but can be used by JSON Schema tools that may not be aware of the OpenAPI context. These examples apply to either input payloads of file uploads or response payloads. From ed267e3b077278d197ea1c9fd254d40a32db25e9 Mon Sep 17 00:00:00 2001 From: Darrel Date: Thu, 28 Jan 2021 12:57:40 -0500 Subject: [PATCH 4/6] Update versions/3.1.0.md --- versions/3.1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versions/3.1.0.md b/versions/3.1.0.md index d8e115f734..d2d13c9117 100644 --- a/versions/3.1.0.md +++ b/versions/3.1.0.md @@ -1536,7 +1536,7 @@ When passing in `multipart` types, boundaries MAY be used to separate sections o * If the property is a primitive, or an array of primitive values, the default Content-Type is `text/plain` * If the property is complex, or an array of complex values, the default Content-Type is `application/json` -* If the property is a `type: string` with a `contentEncoding`, the default Content-Type is `text/plain`, and the media type of the embedded resource is specified in `contentMediaType` +* If the property is a `type: string` with a `contentEncoding`, the default Content-Type is `application/octet-stream` Per the JSON Schema specification, `contentMediaType` without `contentEncoding` present is treated as if `contentEncoding: identity` were present. While useful for embedding text documents such as `text/html` into JSON strings, it is not useful for a `multipart/form-data` part, as it just causes the document to be treated as `text/plain` instead of its actual media type. Use the Encoding Object without `contentMediaType` if no `contentEncoding` is required. From fd8cb80febbb94d77271567aaf23811b0dd30fad Mon Sep 17 00:00:00 2001 From: Darrel Date: Thu, 11 Feb 2021 12:09:50 -0500 Subject: [PATCH 5/6] clarify default encoding content type value. --- versions/3.1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versions/3.1.0.md b/versions/3.1.0.md index d2d13c9117..d8aedcf39c 100644 --- a/versions/3.1.0.md +++ b/versions/3.1.0.md @@ -1583,7 +1583,7 @@ A single encoding definition applied to a single schema property. ##### Fixed Fields Field Name | Type | Description ---|:---:|--- -contentType | `string` | The Content-Type for encoding a specific property. Default value depends on the property type: when `type` is absent - `application/octet-stream`; for primitive types - `text/plain`; for `object` - `application/json`; when `type` is `string` and `contentEncoding` is present, the default Content-Type is `text/plain`, and the media type of the encoded resource is specified in `contentMediaType`; for `array` – the default is defined based on the inner type. The value can be a specific media type (e.g. `application/json`), a wildcard media type (e.g. `image/*`), or a comma-separated list of the two types. +contentType | `string` | The Content-Type for encoding a specific property. Default value depends on the property type: for `object` - `application/json`; for `array` – the default is defined based on the inner type; for all other cases the default is `application/octet-stream`. The value can be a specific media type (e.g. `application/json`), a wildcard media type (e.g. `image/*`), or a comma-separated list of the two types. 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`. 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` or `multipart/form-data`. If a value is explicitly defined, then the value of [`contentType`](#encodingContentType) (implicit or explicit) SHALL be ignored. 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` or `multipart/form-data`. If a value is explicitly defined, then the value of [`contentType`](#encodingContentType) (implicit or explicit) SHALL be ignored. From 90e4d369967621491ceab728c9d3dac19322ee6e Mon Sep 17 00:00:00 2001 From: Darrel Date: Thu, 11 Feb 2021 12:10:54 -0500 Subject: [PATCH 6/6] Describe interaction between JSON Schema contentEncoding and HTTP Content-Encoding header Co-authored-by: Mike Kistler --- versions/3.1.0.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/versions/3.1.0.md b/versions/3.1.0.md index d8aedcf39c..b98a559b20 100644 --- a/versions/3.1.0.md +++ b/versions/3.1.0.md @@ -1433,7 +1433,11 @@ application/json: ##### Considerations for File Uploads -In contrast with the 2.0 specification, `file` input/output content in OpenAPI is described with the same semantics as any other schema type. In contrast with the 3.0 specification, such schemas either omit the `type` (in place of `format: binary`), or use `contentMediaType` and `contentEncoding` with `type: string`. The `contentEncoding` keyword supports all encodings defined in [RFC4648](https://tools.ietf.org/html/rfc4648), including "base64" (which replaces `format: byte`) and "base64url", as well as "quoted-printable" from [RFC2045](https://tools.ietf.org/html/rfc2045#section-6.7). +In contrast with the 2.0 specification, `file` input/output content in OpenAPI is described with the same semantics as any other schema type. + +In contrast with the 3.0 specification, the `format` keyword has no effect on the content-encoding of the schema. JSON Schema offers a `contentEncoding` keyword, which may be used to specify the `Content-Encoding` for the schema. The `contentEncoding` keyword supports all encodings defined in [RFC4648](https://tools.ietf.org/html/rfc4648), including "base64" and "base64url", as well as "quoted-printable" from [RFC2045](https://tools.ietf.org/html/rfc2045#section-6.7). The encoding specified by the `contentEncoding` keyword is independent of an encoding specified by the `Content-Type` header in the request or response or metadata of a multipart body -- when both are present, the encoding specified in the `contentEncoding` is applied first and then the encoding specified in the `Content-Type` header. + +JSON Schema also offers a `contentMediaType` keyword. However, when the media type is already specified by the Media Type Object's key, or by the `contentType` field of an [Encoding Object](#encodingObject), the `contentMediaType` keyword SHALL be ignored if present. Examples: