Skip to content

Multipart form properties codegen is not typesafe #756

Open
@jpsim

Description

@jpsim

Motivation

One of the main benefits I get from using swift-openapi-generator is type safety for client code.

However, for multipart form upload requests, it seems like the property codegen is not typesafe, where all properties just get a generic HTTPBody payload.

For example, given this OpenAPI document:

/uploadFile:
  post:
    operationId: uploadFile
    requestBody:
      required: true
      content:
        multipart/form-data:
          schema:
            type: object
            properties:
              description:
                type: string
                description: A text description of the uploaded file
              count:
                type: integer
                description: An integer value associated with the upload
              imageFile:
                type: string
                format: binary
                description: The image file to upload
            required:
              - description
              - count
              - imageFile

This code is generated for the request body type:

enum Body: Sendable, Hashable {
    enum MultipartFormPayload: Sendable, Hashable {
        struct DescriptionPayload: Sendable, Hashable {
            var body: OpenAPIRuntime.HTTPBody
            init(body: OpenAPIRuntime.HTTPBody) {
                self.body = body
            }
        }
        case description(OpenAPIRuntime.MultipartPart<Operations.UploadFile.Input.Body.MultipartFormPayload.DescriptionPayload>)
        struct CountPayload: Sendable, Hashable {
            var body: OpenAPIRuntime.HTTPBody
            init(body: OpenAPIRuntime.HTTPBody) {
                self.body = body
            }
        }
        case count(OpenAPIRuntime.MultipartPart<Operations.UploadFile.Input.Body.MultipartFormPayload.CountPayload>)
        struct ImageFilePayload: Sendable, Hashable {
            var body: OpenAPIRuntime.HTTPBody
            init(body: OpenAPIRuntime.HTTPBody) {
                self.body = body
            }
        }
        case imageFile(OpenAPIRuntime.MultipartPart<Operations.UploadFile.Input.Body.MultipartFormPayload.ImageFilePayload>)
        case undocumented(OpenAPIRuntime.MultipartRawPart)
    }
    case multipartForm(OpenAPIRuntime.MultipartBody<Operations.UploadFile.Input.Body.MultipartFormPayload>)
}

So at the call site, you're responsible for producing HTTPBody values that respect the schema, but you get no compile-type safety if you make a mistake:

let multipartBody: MultipartBody<Operations.UploadFile.Input.Body.MultipartFormPayload> = [
    .description(.init(payload: .init(body: "This is a test image upload"))),
    .count(.init(payload: .init(body: "42"))),
    .imageFile(.init(payload: .init(body: .init(fileData)))),
]

Ideally, the codegen would produce type safe property payload initializers:

let multipartBody: MultipartBody<Operations.UploadFile.Input.Body.MultipartFormPayload> = [
    .description(.init(payload: .init(value: "This is a test image upload"))),
    .count(.init(payload: .init(value: 42))),
    .imageFile(.init(payload: .init(value: fileData))),
]

and you'd get a compiler failure if you passed say a Swift.String as the count value.

Proposed solution

Ideally, the codegen would produce type safe property payload initializers:

let multipartBody: MultipartBody<Operations.UploadFile.Input.Body.MultipartFormPayload> = [
    .description(.init(payload: .init(value: "This is a test image upload"))),
    .count(.init(payload: .init(value: 42))),
    .imageFile(.init(payload: .init(value: fileData))),
]

and you'd get a compiler failure if you passed say a Swift.String as the count value.

Alternatives considered

No response

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/featureNew feature.status/triageCollecting information required to triage the issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions