Skip to content

Fix OpenAPI3 converter to generate separate operations for multiple content types#8830

Merged
baywet merged 5 commits intomainfrom
copilot/fix-generating-content-types
Oct 28, 2025
Merged

Fix OpenAPI3 converter to generate separate operations for multiple content types#8830
baywet merged 5 commits intomainfrom
copilot/fix-generating-content-types

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Oct 27, 2025

The OpenAPI3-to-TypeSpec converter was discarding non-multipart content types when multipart was present, generating only one operation instead of multiple operations with @sharedRoute.

Changes

  • transform-paths.ts: Split operations with incompatible content types (multipart vs non-multipart) into separate operations with @sharedRoute decorator and content-type-based suffixes
  • generate-operation.ts: Removed filtering logic that discarded non-multipart request bodies when multipart was present
  • Tests: Added coverage for multiple content type scenarios and updated existing test expecting old behavior

Example

Input OpenAPI operation with multiple content types:

requestBody:
  content:
    multipart/form-data:
      schema: { $ref: '#/components/schemas/FooMultiPart' }
    application/json:
      schema: { $ref: '#/components/schemas/FooJson' }

Now generates two operations instead of one:

@sharedRoute
@route("/my-operation") @post op myOperationMultipart(
  @header contentType: "multipart/form-data",
  @multipartBody body: FooMultiPart,
): Bar;

@sharedRoute
@route("/my-operation") @post op myOperationJson(
  @body body: FooJson
): Bar;

Note: Operations with only non-multipart content types continue to be combined with unions (existing behavior).

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • telemetry.astro.build
    • Triggering command: node /home/REDACTED/work/typespec/typespec/website/node_modules/.bin/../astro/astro.js build (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>[Bug]: [tsp-openapi3] Does not generate parameters for all declared content types.</issue_title>
<issue_description>### Describe the bug

When importing an operation that defines different bodies for different content types, only one is generated in the output.

For example, for this definition:

openapi: 3.1.0
info:
  title: My Spec
paths:
  /my-operation:
    post:
      operationId: myOperation
      requestBody:
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/FooMultiPart'
          application/json:
            schema:
              $ref: '#/components/schemas/FooJson'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Bar'

components:
  schemas:
    FooMultiPart:
      type: object
      properties:
        file:
          type: string
          format: binary
        description:
          type: string
      required:
        - file
        - description

    FooJson:
      type: object
      properties:
        name:
          type: string
        age:
          type: integer
      required:
        - name

    Bar:
      type: object
      properties:
        id:
          type: string
        status:
          type: string
      required:
        - id
        - status

It generates:

import "@typespec/http";
import "@typespec/openapi";
import "@typespec/openapi3";

using Http;
using OpenAPI;

@service(#{ title: "My Spec" })
@info(#{})
namespace MySpec;

model FooMultiPart {
  file: HttpPart<bytes>;
  description: HttpPart<string>;
}

model FooJson {
  name: string;
  age?: integer;
}

model Bar {
  id: string;
  status: string;
}

@route("/my-operation") @post op myOperation(
  @header contentType: "multipart/form-data",
  @multipartBody body: FooMultiPart,
): Bar;

Where I would expect (for the operation):

@sharedRoute
@route("/my-operation") @post op myOperationMultipart(
  @header contentType: "multipart/form-data",
  @multipartBody body: FooMultiPart,
): Bar;

@sharedRoute
@route("/my-operation") @post op myOperationJson(
  @header contentType: "application/json",
  @body body: FooJson,
): Bar;

Reproduction

Attached the input used to generate the above example.

repro.zip

Checklist

<agent_instructions>when you are done with the changes, run npx @chronus/chronus add to add a feature changeset. And commit it.</agent_instructions>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 2 commits October 27, 2025 20:22
…PI3 conversion

- Split operations with incompatible content types (multipart vs non-multipart)
- Add @SharedRoute decorator to split operations
- Add tests for multiple content type handling
- Update existing test to reflect new behavior

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>
Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix generation of parameters for all declared content types Fix OpenAPI3 converter to generate separate operations for multiple content types Oct 27, 2025
Copilot AI requested a review from baywet October 27, 2025 20:36
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Oct 28, 2025

All changed packages have been documented.

  • @typespec/openapi3
Show changes

@typespec/openapi3 - feature ✏️

[converter] Generate separate operations with @SharedRoute for operations with multiple incompatible content types (e.g., multipart/form-data and application/json)

Signed-off-by: Vincent Biret <vibiret@microsoft.com>
@baywet baywet marked this pull request as ready for review October 28, 2025 12:47
@baywet baywet enabled auto-merge October 28, 2025 12:47
@baywet baywet added this pull request to the merge queue Oct 28, 2025
Merged via the queue into main with commit cd13f18 Oct 28, 2025
22 checks passed
@baywet baywet deleted the copilot/fix-generating-content-types branch October 28, 2025 13:46
@timotheeguerin timotheeguerin added emitter:openapi3 Issues for @typespec/openapi3 emitter openapi3:converter Issues for @typespec/openapi3 openapi to typespec converter labels Mar 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

emitter:openapi3 Issues for @typespec/openapi3 emitter openapi3:converter Issues for @typespec/openapi3 openapi to typespec converter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: [tsp-openapi3] Does not generate parameters for all declared content types.

3 participants