-
Notifications
You must be signed in to change notification settings - Fork 9.1k
v3.2: Add data vs serialized Example Object fields (Revised) #4671
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v3.2-dev
Are you sure you want to change the base?
Changes from all commits
7a234f7
8427241
2b6971b
e6f707a
2ff66bf
9268148
2d40556
d33c347
fc69e33
ac8bbc0
e74d472
264f23b
d20d0ef
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -2088,23 +2088,28 @@ transactionCallback: | |||||
#### Example Object | ||||||
|
||||||
An object grouping an internal or external example value with basic `summary` and `description` metadata. | ||||||
The examples can show either data suitable for schema validation, or serialized data as required by the containing [Media Type Object](#media-type-object), [Parameter Object](#parameter-object), or [Header Object](#header-object). | ||||||
This object is typically used in fields named `examples` (plural), and is a [referenceable](#reference-object) alternative to older `example` (singular) fields that do not support referencing or metadata. | ||||||
|
||||||
Examples allow demonstration of the usage of properties, parameters and objects within OpenAPI. | ||||||
The various fields and types of examples are explained in more detail under [Working With Examples](#working-with-examples). | ||||||
|
||||||
##### Fixed Fields | ||||||
|
||||||
| Field Name | Type | Description | | ||||||
| ---- | :----: | ---- | | ||||||
| <a name="example-summary"></a>summary | `string` | Short description for the example. | | ||||||
| <a name="example-description"></a>description | `string` | Long description for the example. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation. | | ||||||
| <a name="example-value"></a>value | Any | Embedded literal example. The `value` field and `externalValue` field are mutually exclusive. To represent examples of media types that cannot naturally represented in JSON or YAML, use a string value to contain the example, escaping where necessary. | | ||||||
| <a name="example-data-value"></a>dataValue | Any | An example of the data structure that MUST be valid according to the relevant [Schema Object](#schema-object). If this field is present, `externalDataValue`, `value`, and `externalValue` MUST be absent. | | ||||||
| <a name="example-external-data-value"></a>externalDataValue | `string` | A URI that identifies the data example in a separate document, which is otherwise treated identically to `dataValue` once parsed, with the same validity requirements. If this field is present, then `dataValue`, `value`, and `externalValue` MUST be absent. See also the rules for resolving [Relative URI References](#relative-references-in-api-description-uris). | | ||||||
| <a name="example-serialized-value"></a>serializedValue | `string` | An example of the serialized form of the value, including encoding and escaping as described under [Validating Examples](#validating-examples). If `dataValue` or `externalDataValue` are present, then this field SHOULD contain the serialization of the given data. Otherwise, it SHOULD be the valid serialization of a data value that itself MUST be valid as described for `dataValue`. This field SHOULD NOT be used if the serialization format is JSON, as the data form is easier to work with. If this field is present, `externalSerializedValue`, `value`, and `externalValue` MUST be absent. | | ||||||
| <a name="example-external-serialized-value"></a>externalSerializedValue | `string` | A URI that identifies the serialized example in a separate document, allowing for values not easily or readably expressed in JSON or YAML strings. If `dataValue` or `externalDataValue` are present, then this field SHOULD identify a serialization of the given data. Otherwise, the value SHOULD be a valid serialization as described for `serializedValue`. If this field is present, `serializedValue`, `value`, and `externalValue` MUST be absent. See also the rules for resolving [Relative References](#relative-references-in-api-description-uris). | | ||||||
| <a name="example-value"></a>value | Any | Embedded literal example. The `value` field and `externalValue` field are mutually exclusive. To represent examples of media types that cannot naturally be represented in JSON or YAML, use a string value to contain the example, escaping where necessary. | | ||||||
| <a name="example-external-value"></a>externalValue | `string` | A URI that identifies the literal example. This provides the capability to reference examples that cannot easily be included in JSON or YAML documents. The `value` field and `externalValue` field are mutually exclusive. See the rules for resolving [Relative References](#relative-references-in-api-description-uris). | | ||||||
|
||||||
This object MAY be extended with [Specification Extensions](#specification-extensions). | ||||||
|
||||||
In all cases, the example value SHOULD be compatible with the schema of its associated value. | ||||||
Tooling implementations MAY choose to validate compatibility automatically, and reject the example value(s) if incompatible. | ||||||
See [Validating Examples](#validating-examples) for the exact meaning of "compatible" for each field in this Object. | ||||||
|
||||||
##### Working with Examples | ||||||
|
||||||
|
@@ -2113,18 +2118,65 @@ In all three Objects, this is done through the `examples` (plural) field. | |||||
However, there are several other ways to provide examples: The `example` (singular) field that is mutually exclusive with `examples` in all three Objects, and two keywords (the deprecated singular `example` and the current plural `examples`, which takes an array of examples) in the [Schema Object](#schema-object) that appears in the `schema` field of all three Objects. | ||||||
Each of these fields has slightly different considerations. | ||||||
|
||||||
###### Choosing Which Field(s) to Use | ||||||
|
||||||
The Schema Object's fields are used to show example values without regard to how they might be formatted as parameters or within media type representations. | ||||||
The `examples` array is part of JSON Schema and is the preferred way to include examples in the Schema Object, while `example` is retained purely for compatibility with older versions of the OpenAPI Specification. | ||||||
|
||||||
The mutually exclusive fields in the Parameter, Header, or Media Type Objects are used to show example values which SHOULD both match the schema and be formatted as they would appear as a serialized parameter, serialized header, or within a media type representation. | ||||||
The exact serialization and encoding is determined by various fields in the Parameter Object, Header Object, or in the Media Type Object's [Encoding Object](#encoding-object). | ||||||
The singular `example` field in non-Schema Objects is a shorthand for a single Example Object using only the `value` field, and all guidance for the `value` field applies to it. | ||||||
|
||||||
As originally conceived, the Schema Object's keywords are intended to show data as it would be validated by the containing Schema Object, while the fields in the other Objects were intended to show the serialized media type, parameter, or header. | ||||||
However, the non-Schema Object fields allowed serialized forms that could be "easily" represented as JSON or JSON-compatible YAML to be shown as inline data structures rather than serialized to strings, which means that in the most common case (`application/json` documents), this sort of "serialized" example would be represented in the same way as the validation-ready Schema Object examples. | ||||||
Furthermore, some parameters and headers are simple enough that there is no difference between the serialized and validation-ready forms. | ||||||
|
||||||
Possibly due to these ambiguities, many implementations appear to have implemented the fields that existed prior to version 3.2 of this specification as requiring validation-ready data structures. | ||||||
For this reason, OpenAPI Description authors who want portable behavior with examples that are not for `application/json` media types or trivial strings without any formatting or escaping are RECOMMENDED to use the new fields (`dataValue` or `externalDataValue` for validation-ready data, and `serializedValue` or `externalSerializedValue` for serialized forms). | ||||||
|
||||||
In addition, it can be challenging to correlate the validation-ready Schema Object example with serialized Example Object examples when all are part of shared Objects reached through (possibly multiple) references. | ||||||
Authors who wish to clearly show serialized and unserialized forms of the same data together are RECOMMENDED to use the new fields in the Example Object to do so. | ||||||
|
||||||
Due to the lack of any format for mixing JSON Schema data model-compatible data with binary data (as might happen in a `multipart` media type), such examples can only be given using the `externalSerializedValue` field. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I learned that if three consecutive words belong together, the first two can be connected with a dash (as opposed to German, where the three words would just be strung together into one word). Also this seems to mean "compatible with the data model of JSON Schema", and not "model-compatible with data for JSON Schema" which doesn't make any sense to me. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is to be read as (JSON Schema data model)-compatible, where "JSON Schema data model" is logically one term, so it is correct as written. The phrase "model-compatible with data for JSON Schema" does not make sense to me, and I'm pretty sure that the way I wrote it is compatible with other places where we mention similar things, because I'm pretty sure I wrote those places as well. |
||||||
|
||||||
Because examples using these fields represent the final serialized form of the data, they SHALL _override_ any `example` in the corresponding Schema Object. | ||||||
|
||||||
The singular `example` field in the Parameter, Header, or Media Type Object is concise and convenient for simple examples, but does not offer any other advantages over using Example Objects under `examples`. | ||||||
###### Validating Examples | ||||||
|
||||||
Tooling implementations MAY choose to validate compatibility automatically, and reject the example value(s) if incompatible. | ||||||
handrews marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
The `dataValue` and `externalDataValue` fields are intended to show example data structures suitable for validation by the relevant Schema Object, against which they MUST be valid. | ||||||
|
||||||
The `serializedValue` and `externalSerializedValue` fields show the serialized form according to the format specified by the parent Object. | ||||||
For Example Objects directly under a Media Type Object, this is the serialization to the relevant media type. | ||||||
For Example Objects directly under a Parameter or Header Object, this is the serialization to the appropriate format for use in the appropriate part of a URL or HTTP header (depending on the `in` field in the case of the Parameter Object), including all necessary escaping or encoding (e.g. URI percent-encoding) for the target format. | ||||||
See those Objects for further guidance on what is considered the serialized form for each value of `in`. | ||||||
|
||||||
These values SHOULD be valid examples of the serialized form, however this is not feasible to enforce in all cases due to some data values having multiple valid representations in certain formats as noted in [Appendix B](#appendix-b-data-type-conversion). | ||||||
In some cases, parsing the serialized example and validating the resulting data can eliminate the ambiguity, but in a few cases parsing is also ambiguous, meaning that validation of serialized examples is by necessity a best-effort feature. | ||||||
|
||||||
If either of `dataValue` or `externalDataValue` are also present, the serialized value MUST be a serialization of the data value, and SHOULD be a valid according to the serialization format. | ||||||
|
||||||
When using `serializedValue`, the value MUST be a string that is suitably escaped for inclusion in JSON or YAML in addition to any escaping that is part of the target format. | ||||||
See [Character Encodings and Binary Data](#character-encodings-and-binary-data) for details. | ||||||
|
||||||
The `externalSerializedValue` field supports any format for the external value. | ||||||
Note that this serialization may or may not exactly match what is transmitted over the wire, as different versions of HTTP use different text or binary encodings, and HTTP content may be subject to compression or other transformations not captured in the OpenAPI Description. | ||||||
|
||||||
The `value` and `externalValue` fields were intended to hold serialized values, with `value` allowing inline JSON/YAML structures in place of a string if the serialization format is JSON or otherwise compatible with JSON/YAML. | ||||||
However, many implementations treat them as data values, so these fields are ambiguous and not interoperable in practice. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I haven't found any evidence of implementations that treat There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @hudlow I still don't see how anyone reads any version of 3.x and sees On the other hand, if it is really true that As with the last comment, build a consensus and I'll go with it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (And to anyone reading who is wondering why I'm saying "build a consensus" instead of just accepting the argument, it's because I don't feel able to make a call one way or the other, still prefer my position, and the outcome shouldn't come down to "Henry wins by default because he posted the PR") There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Responded here: #4671 (comment) |
||||||
|
||||||
###### Character Encodings and Binary Data | ||||||
|
||||||
For `externalDataValue`, it is always the parsed data that is significant, not its character encoding. | ||||||
|
||||||
While JSON Schema allows for applying schemas to data outside of its data model, this allowance is intended to support consistent use of Schema Objects, including fields such as `readOnly` that do not impact JSON Schema's validation outcome. | ||||||
No standard format suitable for passing such non-JSON data to JSON Schema has been defined, and therefore data that is outside of the JSON data model cannot be represented with `dataValue` or `externalDataValue`, and MUST use `serializedValue` or `externalSerializedValue`. | ||||||
|
||||||
Note that `serializedValue`, which MUST be a string, is by necessity a sequence of Unicode code points, which will need to be encoded based on the character set or other constraints of the target location. | ||||||
This conversion is purely one of encoding. All escaping necessary to reduce the example to the set of characters valid for the target location (e.g. URI percent-encoding) MUST be included in the `serializedValue`. | ||||||
If the target location's encoding is ambiguous, `externalSerializedValue` can be used to demonstrate the exact serialization, including character set encoding, that is intended. | ||||||
|
||||||
Some examples cannot be represented directly in JSON or YAML. | ||||||
For all three ways of providing examples, these can be shown as string values with any escaping necessary to make the string valid in the JSON or YAML format of documents that comprise the OpenAPI Description. | ||||||
With the Example Object, such values can alternatively be handled through the `externalValue` field. | ||||||
The `serializedValue` field can be used for any textual value with a character set encoding which has an unambiguous mapping to Unicode code points. Since Unicode strings have no inherent binary representation, `serializedValue` cannot be used for binary data. | ||||||
Instead, binary data and other formats that are not always representable as Unicode code points SHOULD use `externalSerializedValue`. | ||||||
|
||||||
##### Example Object Examples | ||||||
|
||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
openapi: 3.2.0 | ||
info: | ||
title: API | ||
version: 1.0.0 | ||
|
||
components: | ||
examples: | ||
CannotHaveBoth: | ||
dataValue: foo | ||
externalDataValue: https://example.com/foo |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
openapi: 3.2.0 | ||
info: | ||
title: API | ||
version: 1.0.0 | ||
|
||
components: | ||
examples: | ||
NoValueWithDataValue: | ||
externalValue: https://example.org/foo | ||
dataValue: foo |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
openapi: 3.2.0 | ||
info: | ||
title: API | ||
version: 1.0.0 | ||
|
||
components: | ||
examples: | ||
NoValueWithDataValue: | ||
externalValue: https://example.org/foo | ||
externalDataValue: https://example.org/foo |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
openapi: 3.2.0 | ||
info: | ||
title: API | ||
version: 1.0.0 | ||
|
||
components: | ||
examples: | ||
NoValueWithDataValue: | ||
externalValue: https://example.org/foo | ||
externalSerializedValue: https://example.org/foo |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
openapi: 3.2.0 | ||
info: | ||
title: API | ||
version: 1.0.0 | ||
|
||
components: | ||
examples: | ||
NoValueWithDataValue: | ||
externalValue: https://example.org/foo | ||
serializedValue: foo |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
openapi: 3.2.0 | ||
info: | ||
title: API | ||
version: 1.0.0 | ||
|
||
components: | ||
examples: | ||
CannotHaveBoth: | ||
value: foo | ||
externalValue: https://example.com/foo |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
openapi: 3.2.0 | ||
info: | ||
title: API | ||
version: 1.0.0 | ||
|
||
components: | ||
examples: | ||
NoValueWithDataValue: | ||
value: foo | ||
dataValue: foo |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
openapi: 3.2.0 | ||
info: | ||
title: API | ||
version: 1.0.0 | ||
|
||
components: | ||
examples: | ||
NoValueWithDataValue: | ||
value: foo | ||
externalDataValue: https://example.org/foo |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
openapi: 3.2.0 | ||
info: | ||
title: API | ||
version: 1.0.0 | ||
|
||
components: | ||
examples: | ||
NoValueWithDataValue: | ||
value: foo | ||
externalSerializedValue: https://example.org/foo |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
openapi: 3.2.0 | ||
info: | ||
title: API | ||
version: 1.0.0 | ||
|
||
components: | ||
examples: | ||
NoValueWithDataValue: | ||
value: foo | ||
serializedValue: foo |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
openapi: 3.2.0 | ||
info: | ||
title: API | ||
version: 1.0.0 | ||
|
||
components: | ||
examples: | ||
CannotHaveBoth: | ||
serializedValue: foo | ||
externalSerializedValue: https://example.com/foo |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Below is my proposal based on ongoing conversations.
One part of this analysis involved mapping out possible interpretations of the existing values:
Some general thoughts:
$ref
behavior is unique for its implicit deserialization and parsing of the target document.On the ambiguity of
externalValue
, while it is conceivable that someone has implemented a$ref
-style abstraction overexternalValue
:value
and the examples don't show a JSON (or YAML) document being referenced for a non-JSON media type.$ref
-style abstraction.Okay, I'm sold, but I think we need to leverage a reference object to clarify that (1) this can be done in-document and that (2) if it's done out-of-document the implicit deserialization/parsing process applies. Hence the proposal for
dataValueReference
above.I actually think the naming asymmetry is a feature and not a bug because:
externalValue
lacks$ref
-style behaviorexternalValue
is a binary serialization unlikeserializedValue
which is a Unicode serializationThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hudlow it sounds like you have a thoroughly thought-through proposal here- I'm not weighing in on the merits because I have only had time to skim it, but it definitely looks worth a proper standalone write-up/PR. I've done two rounds of PRs on this subject and don't have the bandwidth for a third, but if you open your own PR I can close this one in favor of it. Feel free to lift whatever you want from this one, or start over completely, whatever works best for you.
You might also want to take over #4672, and possibly #4648 depending on how that dovetails with your proposal, but the others (particularly #4673) I'll keep and update as needed with the outcome. There are some more examples to update that I hadn't gotten around to posting yet- I can finish those once you've sorted out the new fields, or you can do them if you prefer. But I need to focus on finishing up
multipart
and other media type things such as the media type registry.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@handrews busy week ahead, but I will get something together as soon as I can. I'll aim to have it done by Thursday, but not positive how realistic that is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @hudlow — I have more than enough to occupy the Thursday call with
multipart
and media registry things this week if you want to target next week :-)