OpenAPI-Specification
OpenAPI-Specification copied to clipboard
Parameters for Media Types
Parameters for Media Types
Media Types can support parameters. Yet, to work with them in OpenAPI, one must define them statically against each media type. This has the unfortunate side effect of discouraging use of media type parameters by making them clumsy to manage within the API spec.
content:
text/plain; charset=utf-8:
...
text/plain; charset=iso-8859-1:
...
Without a way to express the parameter, it has little or no semantic value for OpenAPI. Minor variations look like completely different media types. There is little room for negotiation over content parameters unless the API author takes the time to spell out each supported parameter as its own type.
Media Type parameters could be useful in some obvious ways:
- versioning of the media type
- specifying a 'profile' for the media type as described in RFC6906
- negotiating support for embedded resources (i.e. HAL (https://tools.ietf.org/html/draft-kelly-json-hal-08)) , hypermedia style, or level of completeness of a representation.
Private and vendor media types might better manage breaking changes by supporting multiple versions of representation without ever changing endpoints and methods. Perhaps there could be benefits to QA and regression test tooling, being able to validate support for the diversity of representation styles in the API contract. This could be had without having to iterate every parameter combination as a separate media type.
Examples
Versioning
Accept: application/vnd.example-schema+json; version=1.0.4
content:
application/vnd.example-schema+json:
parameters:
version:
type: string
required: false
description: |
The version of the representation.
default: 1.1.0
enum:
- 1.0.3
- 1.0.4
- 1.1.0
schema:
$ref: "https://schemas.example.com/example"
Profile identification
Accept: application/vnd.example-schema+json; profile=https://schemas.example.com/example/profiles/bob
content:
application/vnd.example-schema+json:
parameters:
profile:
type: string
required: false
description: |
The profile (rfc6906) for the representation.
default: "https://schemas.example.com/example/profiles/alice"
enum:
- "https://schemas.example.com/example/profiles/alice"
- "https://schemas.example.com/example/profiles/bob"
schema:
$ref: "https://schemas.example.com/example"
Hypermedia style selection
Accept: application/vnd.example-schema+json; hypermedia=HAL
content:
application/vnd.example-schema+json:
parameters:
hypermedia:
type: string
required: false
description: |
Hypermedia Style. Indicates whether links and other supplemental
resource detail are provided in the representation.
default: JSON_HYPERSCHEMA
enum:
hypermedia:
- NONE
- HAL
- JSON_HYPERSCHEMA
schema:
$ref: "https://schemas.example.com/example"
Added after the original issue report I am inspired by what I read on Roy Fielding's blog entry "REST APIs must be Hypertext Driven".
"A REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state, or in defining extended relation names and/or hypertext-enabled mark-up for existing standard media types. Any effort spent describing what methods to use on what URIs of interest should be entirely defined within the scope of the processing rules for a media type (and, in most cases, already defined by existing media types). [Failure here implies that out-of-band information is driving interaction instead of hypertext.]"
If I understand him correctly, enriching OpenAPI's ability to semantically express media type parameters would improve its ability to convey the kinds of interactions Mr. Fielding expected to be inherent in the resource or resource representation, rather than in other parts of the HTTP message. Conversely, not supporting media type parameters might limit OpenAPI's ability to articulate a nuanced RESTful concept.
I'm right there with you on parameters and your examples for versioning and profile identification, but I think the hypermedia selection stuff is non-standard and we don't want to add anything non-standard to OpenAPI thats going to live in the users actual API.
If we stick the a general mechanism for adding parameters to a media type, I think this could be a great idea. charset, version, etc are all good things to be able to describe as possible in an API.
Thanks Phil. You're right, the hypermedia example is flawed. I'm happy to remove it from the issue or provide other examples if it's helpful.
For consistency, if someone does take this to a PR, fields like type and enum should be wrapped within a standard schema field of type schemaObject.
Right. All of the examples need work.
The operation parameters field may be the best thing to compare for consistency.
Guessing at the changes that might be needed:
- A new
Media Type Parameter Object. Or possibly a subset of the existing Parameters Object? - Add
parametersto the Media Type Object whose type would beMap[Media Type Parameter Object | Reference Object]. - JSON Schema updates. Happy to propose these; would be looking for advice on norms for contributing to the project beyond issue contributions.
Revised Examples
Versioning
Accept: application/vnd.example-schema+json; version=1.0.4
content:
application/vnd.example-schema+json:
parameters:
- name: version
description: Media type version for the representation.
required: false
deprecated: false
schema:
type: string
default: 1.1.0
enum:
- 1.0.3
- 1.0.4
- 1.1.0
examples:
priorVersion:
summary: The most recent prior version.
value: 1.0.4
currentVersion:
summary: The current version.
value: 1.1.0
or
content:
application/vnd.example-schema+json:
parameters:
- $ref: "https://schemas.example.com/example/MediaTypeVersion"
Profile identification
Accept: application/vnd.example-schema+json; profile=https://schemas.example.com/example/profiles/bob
content:
application/vnd.example-schema+json:
parameters:
- name: profile
description: The profile (rfc6906) for the media type
required: false
deprecated: false
schema:
type: string
default: "https://schemas.example.com/example/profiles/alice"
enum:
- "https://schemas.example.com/example/profiles/alice"
- "https://schemas.example.com/example/profiles/bob"
examples:
BobProfile:
summary: The classic Bob profile we all know and love.
value: "https://schemas.example.com/example/profiles/bob"
AliceProfile:
summary: The new and improved.
value: "https://schemas.example.com/example/profiles/alice"
Use of value, not externalValue, as the value is intended to be the URL string, not the profile schema to which the URL refers. Interested if there are disagreements.
or
content:
application/vnd.example-schema+json:
parameters:
- $ref: "https://schemas.example.com/example"
My initial reaction to Phil's tweet, was "OMG No!" . The opaque media type identifier was by design. However, having read this issue and seeing the examples, I am warming up to the idea.
The parameters array is nice for enumerating the possible parameters and the providing the syntax. I have to admit I can never remember the syntax of application/json;odata.metadata=full.
However, once we get into the territory of profile and version parameters, we get to a point where we almost need to be able to have different schemas and examples based on the parameter values. What's the point of documenting profiles if you can't also document the shape that the profile identifies. I'm not sure how you could add that cleanly.
Looking at non-structured media types may put parameters in a different light.
Drawing from the media type registration for PCMU audio. I'm ignoring the fact that the registration assumed PCMU's use in RTP; the same media type might be used to interact with stored audio prompts, songs, etc. via HTTP.
GET /songs/happy-birthday
Accept: audio/PCMU;rate=44100;channels=2;q=0.9, audio/PCMU;rate=8000;q=0.8, audio/*;q=0.5
content:
audio/PCMU:
parameters:
- name: rate
description: The bitrate for the audio
required: true
schema:
type: string
default: "8000"
enum:
- "6000"
- "8000"
- "11025"
- "16000"
- "22050"
- "32000"
- "44100"
- "48000"
- "64000"
- "88200"
- "96000"
- "176400"
- "192000"
- name: channels
description: The number of audio channels
required: false
schema:
type: integer
default: 1
enum:
- 1
- 2
Benefit to API Author and Client Developer
To be realistic, I took the options in the bitrate enum from Adobe Audition. With thirteen bitrate options and a mono/stereo option, OpenAPI 3.0 requires twenty-six independent media types to express the options. Not only is it inefficient, but it implicitly and wrongly suggests that the multiple media types are different. They are not.
On the client side, the cost of reducing the options into meaningful handling is higher than it ought to be. In this example, not being able to express this aspect of HTTP forces the author to either take on inefficiency or solve the same problem by other means. Query parameters are probably the next best option, but if the media type authors intended for clients to interact with the resource and representations using parameters, why force the API author to develop an alternative?
Addressing Examples
The examples question is interesting. Using the plural examples: object, one has the opportunity to name each example. There isn't explicit mapping (yet proposed). Authors have always had to question how far to go with examples. JSON already provides so much flexibility that documenting all permutations may be unrealistic. I'm not sure mapping the examples to parameters is a problem that must be solved; maybe OpenAPI already has what it needs for examples.
The Value of Versioning
Versioning and profiles are just examples. It may not even be good practice to version some media types; I've seen commentary in this direction. But having versioning could enable organizations offering SLA-supported API products to gracefully revise their APIs' private media types and schemas without changing the API structurally. In this case, media type parameters would enable client developers to step through schema updates gracefully, selecting the supported earlier representation while being informed of updates.
I hope we can improve OpenAPI's semantic support for Content Negotiation, one of HTTP's most powerful features. Best practices for defining media types will continue to evolve, and our examples are probably just scratching the surface. Looking back to Roy Fielding's statement on media types, I believe this is consistent with his intent.
JSON:API v1.1 too has a similar requirement in order to express support for extensions and profiles.
Alternative Proposal:
-
Introduce new Parameter type -
media-typewhich could be grouped with existing parameters. -
Introduce parameters in Responses where
incan contain only two values -headerormedia-typeinstead of header objects. -
Support a discriminator(Discriminator object) field in Media-Type Object which would override the existing
schemafield.
Drawbacks:
- Discriminating schema against multiple parameters won't be possible.