Skip to content

v3.2: Allow Media Type and Encoding re-use #4728

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

Open
wants to merge 1 commit into
base: v3.2-dev
Choose a base branch
from

Conversation

handrews
Copy link
Member

Add the Media Type Object and Encoding Object to the Components Object, and allow a Reference Object anywhere they are allowed. To ensure that re-usable Objects can be documented clearly, add a description field to both Objects. [Note: If adding description is more controversial than just supporting re-use, I could be persuaded to drop it.]

One important thing to do as a release approaches is to try to use the new features more. As I have done this, I've realized that our increased usage and functionality of Media Type and Encoding Objects (which now handle streaming JSON, and are expected to handle a wider variety of multipart media types and be more useful with XML) make re-use of those objects a much more compelling prospect. While your average application/json Media Type Object is trivial, once you start using more complex media types, the duplication becomes substantial.

Explanation and Examples

One use case might come from @jeremyfiel who, IIRC, works with an API where multipart/mixed usage that combines JSON metadata with binary data is common. Depending on how complex and common that format is, the media type object might be worth re-using in many places. We're expanding the support for multipart a lot, and in general multipart Media Type Objects are quite complex, with many Encoding Objects (which may have substantial commonality themselves if similar parts are used in different multipart configurations) plus Example Objects.

But to bring things back to a concrete example, here is a pattern that was at one time fairly common- allowing querying either through the URL query string, or through putting the query contents in the body of a POST in case the URL got too long (although here I am showing QUERY instead of POST).

Assume both of the examples to follow start with these components (I pulled them out to make the length comparisons more obvious):

openapi: 3.2.0 
info:
  title: API
components:
  schemas:
    PetFields:
      enum: 
      - name
      - petType
      - color
      - gender
      - breed
    Pet:  
      propertyNames:
        $ref: '#/components/schemas/PetFields'
      additionalProperties:
        type: string
      required:
      - name
      - petType
    ListForQuery:
      type: array 
      items:
        type: string      
    PetQueryLists:
      additionalProperties:
        $ref: '#/components/schemas/ListForQuery'
      propertyNames:
        $ref: '#/components/schemas/PetFields'
  examples:
    CatSearch:
      summary: Search for Persian or Ragamuffin cats
      dataValue:
        petType:
        - Cat
        breed:
        - Persian
        - Ragamuffin
      serializedValue: petType=Cat&breed=Persian,Ragamuffin
  responses:
    Pets:
      content:
        application/json:
          schema:
            type: array
              items:
                $ref: '#/components/schemas/Pet'

Here it is with re-use, at 53 additional lines:

...
components:
   ...
  parameters:
    PetQuery:
      name: pets
      in: querystring
      content:
        application/x-www-form-urlencoded:
          $ref: '#/components/mediaTypes/PetQuery'
      examples:
        CatSearch:
          $ref: '#/components/examples/CatSearch'
  mediaTypes:
    PetQuery:
      description: A query format for pets.
      schema:
        $ref: '#/components/schemas/PetQueryLists'
      encoding:
        name: 
          $ref: '#/components/encodings/OrValuesNoExplode'
        petType:
          $ref: '#/components/encodings/OrValuesNoExplode'
        color:
          $ref: '#/components/encodings/OrValuesNoExplode'
        gender:
          $ref: '#/components/encodings/OrValuesNoExplode'
        breed:
          $ref: '#/components/encodings/OrValuesNoExplode'
      examples:
        CatSearch:
          $ref: '#/components/examples/CatSearch'
  encodings:
    OrValuesNoExplode:
      description: |
        This parameter takes multiple comma-separated
        values and returns items that match at least
        one of the values in the list.
      style: form
      explode: false
paths:
  /pets:
    get:
      parameters:
      - $ref: '#/components/parameters/PetQuery'
      responses:
        "200":
          $ref: '#/components/responses/Pets'
    query:
      requestBody:
        content:
          application/x-www-form-urlencoded:
            $ref: '#/components/mediaTypes/PetQuery'
      responses:
        "200":
          $ref: '#/components/responses/Pets'

Without re-use, it takes 66 additional lines. However, there is another wrinkle if we wanted to put in some descriptive text, which we'll look at afterwards:

...
components:
   ...
  parameters:
    PetQuery: 
      name: pets
      in: querystring
      content:
        application/x-www-form-urlencoded:
          schema:
            $ref: '#/components/schemas/PetQueryLists'
          encoding:
            name:
              style: form
              explode: false
            petType:
              style: form
              explode: false
            color:
              style: form
              explode: false
            gender:
              style: form
              explode: false
            breed:
              style: form
              explode: false
          examples:
            CatSearch:
              $ref: '#/components/examples/CatSearch'
      examples:
        CatSearch:
          $ref: '#/components/examples/CatSearch'
paths:
  /pets:
    get:
      parameters:
      - $ref: '#/components/parameters/PetQuery'
      responses:
        "200":
          $ref: '#/components/responses/Pets'
    query:
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/PetQueryLists'
            encoding:
              name:
                style: form
                explode: false
              petType:
                style: form
                explode: false
              color:
                style: form
                explode: false
              gender:
                style: form
                explode: false
              breed:
                style: form
                explode: false
            examples:
              CatSearch:
                $ref: '#/components/examples/CatSearch'
      responses:
        "200":
          $ref: '#/components/responses/Pets'

These examples are light on describing the query behavior. If we add description fields to the above version, we can describe the multi-value behavior of every parameter by adding it to #/components/encodings/OrValuesNoExplode. But if we want to document that in the non-re-use version, there is nowhere to put it on a per-parameter basis. The Encoding Object does not allow it, and the Schema Object is not really where that description should go as the Schema might be used for other things. So if we really want per-parameter descriptions, we'd have to replace our one in: querystring parameter with individual in: query parameters, and now everything is even longer (70 lines, partially because there wasn't any point in having a parameters components section anymore which reduced the count). And in this version, there's nowhere to put an example of the entire query string, either!

paths:
  /pets:
    get:  
      parameters:
      - name: name
        in: query 
        description: Multiple comma-separated values are OR'd. 
        schema:
          $ref: '#/components/schemas/ListForQuery'
        style: form
        explode: false 
      - name: petType
        in: query 
        description: Multiple comma-separated values are OR'd. 
        schema:
          $ref: '#/components/schemas/ListForQuery'
        style: form
        explode: false 
      - name: color 
        in: query 
        description: Multiple comma-separated values are OR'd. 
        schema:
          $ref: '#/components/schemas/ListForQuery'
        style: form
        explode: false 
      - name: gender
        in: query 
        description: Multiple comma-separated values are OR'd. 
        schema:
          $ref: '#/components/schemas/ListForQuery'
        style: form
        explode: false 
      - name: breed 
        in: query 
        description: Multiple comma-separated values are OR'd. 
        schema:
          $ref: '#/components/schemas/ListForQuery'
        style: form
        explode: false 
      responses:
        "200":
          $ref: '#/components/responses/Pets'
    query:
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/PetQueryLists'
            encoding:
              name:
                style: form
                explode: false
              petType:
                style: form
                explode: false
              color:
                style: form
                explode: false
              gender:
                style: form
                explode: false
              breed:
                style: form
                explode: false
            examples:
              CatSearch:
                $ref: '#/components/examples/CatSearch'
      responses:
        "200":
          $ref: '#/components/responses/Pets'
  • schema changes are included in this pull request
  • schema changes are needed for this pull request but not done yet
  • no schema changes are needed for this pull request

@handrews handrews requested review from a team as code owners June 16, 2025 02:02
@handrews handrews added the media and encoding Issues regarding media type support and how to encode data (outside of query/path params) label Jun 16, 2025
@handrews handrews changed the title v3.3: Allow Media Type and Encoding re-use v3.2: Allow Media Type and Encoding re-use Jun 16, 2025
@handrews handrews added this to the v3.2.0 milestone Jun 16, 2025
Add the Media Type Object and Encoding Object to the Components Object,
and allow a Reference Object anywhere they are allowed.

To ensure that re-usable Objects can be documented clearly, add
a `description` field to both Objects.
@handrews
Copy link
Member Author

Accidentally pushed an intermediate commit, had to force-push to fix. This should be correct now- also fixed the title as this is proposed for 3.2 based on trying to use new 3.2 features in non-trivial ways.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
media and encoding Issues regarding media type support and how to encode data (outside of query/path params)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant