#6
feat: multipart/form-data file uploads
Summary
Operations whose request body is multipart/form-data (file upload endpoints — audio transcription, image processing, document import) didn't work: providing any body flag threw "Body field flags are only supported for JSON request bodies", and providing none silently sent {} with a boundary-less Content-Type: multipart/form-data header.
Now body properties declared as type: string, format: binary become file flags that take a filesystem path. For a spec like:
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
file: { type: string, format: binary }
model_id: { type: string }
required: [file, model_id]the generated command is:
mycli transcriptions create --file ./audio.mp3 --model_id scribe_v1- Paths are Ajv-validated as strings, checked for existence (
File not found: ./audio.mp3 (--file)), then assembled into aFormDatabody viaBun.file()so theRequestconstructor derives the boundary --curlemits a runnable command:-F 'file=@/path'for files,--form-string 'name=value'for scalars, with the Content-Type header suppressed so curl generates its own boundary- Help renders file flags as
--file <path> PreparedRequestgains a serializablebodyPartsfield (for files, the value is the source path)- A required multipart body with no flags errors instead of silently sending
{}; nested fields under multipart error clearly; JSON stays preferred when an operation offers both content types - File uploads require Bun (Node throws a clear error)
Scope decisions: path strings only (no Blob-in-flags for the programmatic client), multipart only (no form-urlencoded), no arrays of files.
Also includes a prefactoring commit deleting the dead loadBody/BodyInput module and the unused bodyFlags field.
Test plan
-
bun test— 292 pass (13 new: FormData round-trip, curl shape, file-not-found, missing required field, empty-body error, Ajv scalar validation, nested-field rejection, content-type preference, execute round-trip, render output) -
bun run typecheckclean;biome check srcclean (biome cifails only on generateddist/output, pre-existing) - End-to-end: a compiled standalone binary from a spec with a multipart speech-to-text endpoint produces
curl -sS -X POST -F 'file=@.../sample.mp3' --form-string 'model_id=scribe_v1' 'https://api.example.com/v1/speech-to-text'