Skip to content

ExamplesFile Upload

File Upload

FormData file upload with progress tracking. Courier auto-detects FormData and handles encoding.

both modes

Simple Upload

Single-request file upload. FormData is auto-detected by courier.

ts
import { caller } from "@/lib/caller"

const formData = new FormData()
formData.append("file", file)
formData.append("description", "My upload")

// FormData is auto-detected — courier sends multipart/form-data
const result = await caller.files.upload(formData)
caller.files.uploadSANDBOX
idle
// run the request to see the response
Upload docs

Upload with Progress

A browser reports an upload's progress over XMLHttpRequest, since fetch has none — every 100 ms or so, a step of several percent each on a slow link. smoothProgress moves the bar between the reports: never ahead of the upload, never back, and at rest at 100%.

ts
import { smoothProgress } from "@noverax/courier"
import { caller } from "@/lib/caller"

const formData = new FormData()
formData.append("file", file)

// The browser reports progress in steps: smoothProgress moves the bar between them
const result = await caller.files.with({
  onUploadProgress: smoothProgress((progress) => {
    setProgress(progress.percent * 100)
  }),
}).upload(formData)
caller.files.with({ onUploadProgress }).uploadSANDBOX

Both bars follow the same upload. On localhost it is near instant: throttle the network in DevTools, or send one in the upload guide's lab, which reads it at the pace you pick.

idle
// run the request to see the response
smoothProgress

Source Definition

FormData is automatically detected. No special configuration needed.

ts
import { courier, defineGroup } from "@noverax/courier/define"

const { endpoint } = courier()

const files = defineGroup({
  prefix: "upload",
  endpoints: {
    // FormData auto-detected — no bodySerializer needed
    // Empty files are automatically removed before sending
    upload: endpoint.post("").variables<FormData>().response<UploadResponse>(),
  },
})

When variables is FormData, courier skips JSON encoding and sends it as multipart/form-data. Empty files are automatically removed before sending.