apple / apple/swift-openapi-generator

Multipart form properties codegen is not typesafe

Open
#756 8 comments 0 reactions 0 assignees View on GitHub
kind/feature status/triage
Dominant language
Swift
Stars
2k
Forks
182
Avg merge
13h 28m
Merged PRs (30d)
5

Description

### 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:

```yaml
/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:

```swift
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)
struct CountPayload: Sendable, Hashable {
var body: OpenAPIRuntime.HTTPBody
init(body: OpenAPIRuntime.HTTPBody) {
self.body = body
}
}
case count(OpenAPIRuntime.MultipartPart)
struct ImageFilePayload: Sendable, Hashable {
var body: OpenAPIRuntime.HTTPBody
init(body: OpenAPIRuntime.HTTPBody) {
self.body = body
}
}
case imageFile(OpenAPIRuntime.MultipartPart)
case undocumented(OpenAPIRuntime.MultipartRawPart)
}
case multipartForm(OpenAPIRuntime.MultipartBody)
}
```

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:

```swift
let multipartBody: MultipartBody = [
.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:

```swift
let multipartBody: MultipartBody = [
.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:

```swift
let multipartBody: MultipartBody = [
.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_

Contributor guide

Open the contributing guide

Research direction

Start by generating the multipart request body from the OpenAPI document in the issue and inspect the generated Body.MultipartFormPayload types. Trace the multipart form property code generation, then verify that string, integer, and binary properties expose schema-appropriate initializers and reject mismatched values at compile time.

Written by the indexing model from the issue text.

Assessment

Tech stack
openapi, swift
Domain
api, tooling
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.