Skip to content
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

Parameters for Media Types #2342

Open
cjaccino opened this issue Sep 6, 2020 · 7 comments
Open

Parameters for Media Types #2342

cjaccino opened this issue Sep 6, 2020 · 7 comments
Labels
headers media and encoding Issues regarding media type support and how to encode data (outside of query/path params) request matching Matching requests to URL templates, media types, etc.

Comments

@cjaccino
Copy link

cjaccino commented Sep 6, 2020

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.

@philsturgeon
Copy link
Contributor

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.

@cjaccino
Copy link
Author

cjaccino commented Nov 4, 2020

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.

@MikeRalphson
Copy link
Member

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.

@cjaccino
Copy link
Author

cjaccino commented Nov 4, 2020

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 parameters to the Media Type Object whose type would be Map[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"

@darrelmiller
Copy link
Member

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.

@cjaccino
Copy link
Author

cjaccino commented Nov 6, 2020

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.

@jugaadi
Copy link

jugaadi commented Mar 28, 2022

JSON:API v1.1 too has a similar requirement in order to express support for extensions and profiles.

Alternative Proposal:

  1. Introduce new Parameter type - media-type which could be grouped with existing parameters.

  2. Introduce parameters in Responses where in can contain only two values - header or media-type instead of header objects.

  3. Support a discriminator(Discriminator object) field in Media-Type Object which would override the existing schema field.

Drawbacks:

  1. Discriminating schema against multiple parameters won't be possible.

@handrews handrews added the request matching Matching requests to URL templates, media types, etc. label Jan 28, 2024
@handrews handrews added media and encoding Issues regarding media type support and how to encode data (outside of query/path params) headers labels May 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
headers media and encoding Issues regarding media type support and how to encode data (outside of query/path params) request matching Matching requests to URL templates, media types, etc.
Projects
None yet
Development

No branches or pull requests

6 participants