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
FormDatais sent as it is. liaise sets noContent-Typefor it, and the runtime setsmultipart/form-datawith the boundary that separates the parts. Don’t setContent-Typeyourself on aFormDataupload, or the boundary is lost (MDN).- The upload’s answer is read as JSON, the default, so
uploaded.datais{ url: string }. responseType: 'blob'reads the body as aBlob. For anArrayBufferor a string, use'arrayBuffer'or'text'(Reading responses).- Other bodies work too. A
Blob, anArrayBufferor aReadableStreampassed as the params is sent asapplication/octet-stream(Request bodies). AReadableStreamcan be sent only once, so to retry an upload, read the stream into aBloborArrayBufferfirst (Stream bodies).
Next: Send a query param with a JSON body splits a call’s params between the query string and the body.