Upload a file alongside text fields using `multipart/form-data` — the same mechanism a browser file-upload form uses.
Upload a file alongside text fields using `multipart/form-data` — the same mechanism a browser file-upload form uses.
curl -X POST https://api.example.com/upload \
-F 'file=@./photo.jpg;type=image/jpeg' \
-F 'title=My photo'const form = new FormData();
form.append('file', fileInput.files[0]);
form.append('title', 'My photo');
await fetch('https://api.example.com/upload', {
method: 'POST',
body: form // do NOT set Content-Type manually
});import requests
with open('photo.jpg', 'rb') as f:
res = requests.post('https://api.example.com/upload',
files={'file': ('photo.jpg', f, 'image/jpeg')},
data={'title': 'My photo'})
res.raise_for_status()curl's `-F` turns each field into a part, and `@` attaches the actual file contents (`<` would put file contents as a plain field value). You can set a part's Content-Type with `;type=` and its transmitted name with `filename=`.
Key pitfall: do not set the Content-Type header yourself. Multipart requires a random `boundary` string separating the parts; when you pass a `FormData` to `fetch` or `files=` to `requests`, the library computes the boundary and fills the header for you. Manually setting just `multipart/form-data` omits the boundary and the server fails to parse it.
A file over the server's limit yields 413 Payload Too Large, and a disallowed type yields 415 Unsupported Media Type. For very large files, consider chunked/resumable uploads or a direct presigned-URL upload to storage.