liaisev5.3.1
/Upload and download files

Recipes

Upload and download files

Use this when a form uploads a file, such as an avatar, or the app offers a file to download. Neither one is JSON: an upload goes out as multipart form data, and a download comes back as bytes.

Pass FormData as the params to upload, and set responseType: 'blob' to download.

import { createApi, defineRequest } from 'liaise'

// Upload: pass FormData as the params. liaise sends it as-is, and the
// runtime sets the multipart Content-Type with its boundary.
const uploadAvatar = defineRequest<{ url: string }, FormData>()({
  method: 'POST',
  path: '/avatar',
})

// Download: ask for a Blob instead of JSON.
const downloadFile = defineRequest<Blob>()({
  method: 'GET',
  path: '/files/:id',
  responseType: 'blob',
})

const api = createApi({ baseUrl: '/api', requests: { uploadAvatar, downloadFile } })

Calling them:

// Upload the file the user picked
const form = new FormData()
form.append('file', file)
const uploaded = await api.uploadAvatar(form)
if (!uploaded.error) show(uploaded.data.url)

// Download a file and link to it
const { data, error } = await api.downloadFile({ id: '9' })
if (!error) link.href = URL.createObjectURL(data)

file is a File from an <input type="file">, and link is an <a> element.

Why it works

  • FormData is sent as it is. liaise sets no Content-Type for it, and the runtime sets multipart/form-data with the boundary that separates the parts. Don’t set Content-Type yourself on a FormData upload, or the boundary is lost (MDN).
  • The upload’s answer is read as JSON, the default, so uploaded.data is { url: string }.
  • responseType: 'blob' reads the body as a Blob. For an ArrayBuffer or a string, use 'arrayBuffer' or 'text' (Reading responses).
  • Other bodies work too. A Blob, an ArrayBuffer or a ReadableStream passed as the params is sent as application/octet-stream (Request bodies). A ReadableStream can be sent only once, so to retry an upload, read the stream into a Blob or ArrayBuffer first (Stream bodies).

Next: Send a query param with a JSON body splits a call’s params between the query string and the body.

esc