apple / swift-openapi-generator

Generate Swift client and server code from an OpenAPI document.
https://swiftpackageindex.com/apple/swift-openapi-generator/documentation
Apache License 2.0
1.45k stars 120 forks source link

Multipart content-type expectation for binary file part fails at OpenAPI 3.1.0 #666

Closed atacan closed 2 weeks ago

atacan commented 2 weeks ago

Description

When a multipart request schema has a binary part

properties:
  file:
    type: string
    format: binary

with openapi: 3.0.0 we get

    try converter.verifyContentTypeIfPresent(
        in: headerFields,
        matches: "application/octet-stream"
    )

however with openapi: 3.1.0 we get

    try converter.verifyContentTypeIfPresent(
        in: headerFields,
        matches: "text/plain"
    )

This throws the following error, when the server receives the request

error.type=Server error - cause description: 'User handler threw an error.', underlying error: Unexpected content type, expected: text/plain, received: application/octet-stream

Reproduction

Package version(s)

.
├── hummingbird<https://github.com/hummingbird-project/hummingbird.git@2.3.0>
│   ├── swift-async-algorithms<https://github.com/apple/swift-async-algorithms.git@1.0.2>
│   │   └── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
│   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
│   ├── swift-log<https://github.com/apple/swift-log.git@1.6.1>
│   ├── swift-http-types<https://github.com/apple/swift-http-types.git@1.3.0>
│   ├── swift-metrics<https://github.com/apple/swift-metrics.git@2.5.0>
│   ├── swift-distributed-tracing<https://github.com/apple/swift-distributed-tracing.git@1.1.2>
│   │   └── swift-service-context<https://github.com/apple/swift-service-context.git@1.1.0>
│   ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
│   │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│   │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
│   │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
│   ├── swift-nio-extras<https://github.com/apple/swift-nio-extras.git@1.24.1>
│   │   ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
│   │   │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│   │   │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
│   │   │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
│   │   ├── swift-nio-http2<https://github.com/apple/swift-nio-http2.git@1.34.1>
│   │   │   ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
│   │   │   │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│   │   │   │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
│   │   │   │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
│   │   │   └── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│   │   └── swift-http-types<https://github.com/apple/swift-http-types.git@1.3.0>
│   ├── swift-nio-http2<https://github.com/apple/swift-nio-http2.git@1.34.1>
│   │   ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
│   │   │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│   │   │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
│   │   │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
│   │   └── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│   ├── swift-nio-ssl<https://github.com/apple/swift-nio-ssl.git@2.29.0>
│   │   └── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
│   │       ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│   │       ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
│   │       └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
│   ├── swift-nio-transport-services<https://github.com/apple/swift-nio-transport-services.git@1.23.0>
│   │   ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
│   │   │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│   │   │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
│   │   │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
│   │   └── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│   ├── swift-service-lifecycle<https://github.com/swift-server/swift-service-lifecycle.git@2.6.2>
│   │   ├── swift-log<https://github.com/apple/swift-log.git@1.6.1>
│   │   └── swift-async-algorithms<https://github.com/apple/swift-async-algorithms.git@1.0.2>
│   │       └── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
│   └── async-http-client<https://github.com/swift-server/async-http-client.git@1.23.1>
│       ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
│       │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│       │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
│       │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
│       ├── swift-nio-ssl<https://github.com/apple/swift-nio-ssl.git@2.29.0>
│       │   └── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
│       │       ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│       │       ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
│       │       └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
│       ├── swift-nio-http2<https://github.com/apple/swift-nio-http2.git@1.34.1>
│       │   ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
│       │   │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│       │   │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
│       │   │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
│       │   └── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│       ├── swift-nio-extras<https://github.com/apple/swift-nio-extras.git@1.24.1>
│       │   ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
│       │   │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│       │   │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
│       │   │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
│       │   ├── swift-nio-http2<https://github.com/apple/swift-nio-http2.git@1.34.1>
│       │   │   ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
│       │   │   │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│       │   │   │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
│       │   │   │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
│       │   │   └── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│       │   └── swift-http-types<https://github.com/apple/swift-http-types.git@1.3.0>
│       ├── swift-nio-transport-services<https://github.com/apple/swift-nio-transport-services.git@1.23.0>
│       │   ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
│       │   │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│       │   │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
│       │   │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
│       │   └── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│       ├── swift-log<https://github.com/apple/swift-log.git@1.6.1>
│       ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
│       └── swift-algorithms<https://github.com/apple/swift-algorithms@1.2.0>
│           └── swift-numerics<https://github.com/apple/swift-numerics.git@1.0.2>
├── swift-argument-parser<https://github.com/apple/swift-argument-parser.git@1.5.0>
├── swift-openapi-generator<https://github.com/apple/swift-openapi-generator.git@1.4.0>
│   ├── swift-algorithms<https://github.com/apple/swift-algorithms@1.2.0>
│   │   └── swift-numerics<https://github.com/apple/swift-numerics.git@1.0.2>
│   ├── openapikit<https://github.com/mattpolzin/OpenAPIKit@3.3.0>
│   │   └── yams<https://github.com/jpsim/Yams@5.1.3>
│   ├── yams<https://github.com/jpsim/Yams@5.1.3>
│   └── swift-argument-parser<https://github.com/apple/swift-argument-parser.git@1.5.0>
├── swift-openapi-runtime<https://github.com/apple/swift-openapi-runtime.git@1.6.0>
│   └── swift-http-types<https://github.com/apple/swift-http-types.git@1.3.0>
└── swift-openapi-hummingbird<https://github.com/swift-server/swift-openapi-hummingbird.git@2.0.1>
    ├── swift-openapi-runtime<https://github.com/apple/swift-openapi-runtime.git@1.6.0>
    │   └── swift-http-types<https://github.com/apple/swift-http-types.git@1.3.0>
    └── hummingbird<https://github.com/hummingbird-project/hummingbird.git@2.3.0>
        ├── swift-async-algorithms<https://github.com/apple/swift-async-algorithms.git@1.0.2>
        │   └── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
        ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
        ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
        ├── swift-log<https://github.com/apple/swift-log.git@1.6.1>
        ├── swift-http-types<https://github.com/apple/swift-http-types.git@1.3.0>
        ├── swift-metrics<https://github.com/apple/swift-metrics.git@2.5.0>
        ├── swift-distributed-tracing<https://github.com/apple/swift-distributed-tracing.git@1.1.2>
        │   └── swift-service-context<https://github.com/apple/swift-service-context.git@1.1.0>
        ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
        │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
        │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
        │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
        ├── swift-nio-extras<https://github.com/apple/swift-nio-extras.git@1.24.1>
        │   ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
        │   │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
        │   │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
        │   │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
        │   ├── swift-nio-http2<https://github.com/apple/swift-nio-http2.git@1.34.1>
        │   │   ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
        │   │   │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
        │   │   │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
        │   │   │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
        │   │   └── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
        │   └── swift-http-types<https://github.com/apple/swift-http-types.git@1.3.0>
        ├── swift-nio-http2<https://github.com/apple/swift-nio-http2.git@1.34.1>
        │   ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
        │   │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
        │   │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
        │   │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
        │   └── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
        ├── swift-nio-ssl<https://github.com/apple/swift-nio-ssl.git@2.29.0>
        │   └── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
        │       ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
        │       ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
        │       └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
        ├── swift-nio-transport-services<https://github.com/apple/swift-nio-transport-services.git@1.23.0>
        │   ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
        │   │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
        │   │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
        │   │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
        │   └── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
        ├── swift-service-lifecycle<https://github.com/swift-server/swift-service-lifecycle.git@2.6.2>
        │   ├── swift-log<https://github.com/apple/swift-log.git@1.6.1>
        │   └── swift-async-algorithms<https://github.com/apple/swift-async-algorithms.git@1.0.2>
        │       └── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
        └── async-http-client<https://github.com/swift-server/async-http-client.git@1.23.1>
            ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
            │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
            │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
            │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
            ├── swift-nio-ssl<https://github.com/apple/swift-nio-ssl.git@2.29.0>
            │   └── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
            │       ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
            │       ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
            │       └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
            ├── swift-nio-http2<https://github.com/apple/swift-nio-http2.git@1.34.1>
            │   ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
            │   │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
            │   │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
            │   │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
            │   └── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
            ├── swift-nio-extras<https://github.com/apple/swift-nio-extras.git@1.24.1>
            │   ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
            │   │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
            │   │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
            │   │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
            │   ├── swift-nio-http2<https://github.com/apple/swift-nio-http2.git@1.34.1>
            │   │   ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
            │   │   │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
            │   │   │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
            │   │   │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
            │   │   └── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
            │   └── swift-http-types<https://github.com/apple/swift-http-types.git@1.3.0>
            ├── swift-nio-transport-services<https://github.com/apple/swift-nio-transport-services.git@1.23.0>
            │   ├── swift-nio<https://github.com/apple/swift-nio.git@2.76.1>
            │   │   ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
            │   │   ├── swift-collections<https://github.com/apple/swift-collections.git@1.1.4>
            │   │   └── swift-system<https://github.com/apple/swift-system.git@1.4.0>
            │   └── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
            ├── swift-log<https://github.com/apple/swift-log.git@1.6.1>
            ├── swift-atomics<https://github.com/apple/swift-atomics.git@1.2.0>
            └── swift-algorithms<https://github.com/apple/swift-algorithms@1.2.0>
                └── swift-numerics<https://github.com/apple/swift-numerics.git@1.0.2>

Expected behavior

binary file part should expect octet/stream instead of plain text.

Environment

swift-driver version: 1.115 Apple Swift version 6.0 (swiftlang-6.0.0.9.10 clang-1600.0.26.2)
Target: arm64-apple-macosx15.0

Additional information

No response

czechboy0 commented 2 weeks ago

Hi @atacan,

yes this is expected, see OpenAPI 3.1.0:

In contrast with the 3.0 specification, the format keyword has no effect on the content-encoding of the schema. JSON Schema offers a contentEncoding keyword, which may be used to specify the Content-Encoding for the schema.

https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#considerations-for-file-uploads

In 3.1.0, just change format: binary to contentEncoding: binary

atacan commented 2 weeks ago

Thank you