Skip to content

Multipart form properties codegen is not typesafe #756

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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