I’m having problems with the web frontend for a FastAPI endpoint that accepts a list of image files. When I attempt to upload the files, I receive the following error:
Error 422: Unprocessable entity
Here’s the code for my FastAPI endpoint:
@app.post("/new-album") def new_album(name: str = Form(...), images: List[UploadFile] = Form(...)): # ... process images ... return {"Message": f" Album {name} created with {len[images]} images."}
Here’s my client-side JavaScript:
function create_album() { var albumNameInput = document.getElementById('albumNameInput'); var imagesInput = document.getElementById('imagesInput'); var formData = new FormData(); formData.append('name', albumNameInput.value); formData.append('images', imagesInput.files[0]); fetch('/new-album', { method: 'POST', body: formData, }) .then(response => response.json()); } document.querySelector("form").addEventListener("submit", create_album);
Since I’m uploading files, I’ve tried to add the header Content-Type: multipart/form-data
to my request, but that just produces this error instead:
Error 400: Bad Request
What am I doing wrong and how can I get this working?
On the endpoint, the default value of images
is set to Form(...)
, when it should be File(...)
. This can also be left out when using UploadFile
as per FastAPI’s documentation. So we can change the endpoint code as follows:
@app.post("/new-album") def new_album(name: str = Form(...), images: List[UploadFile]): # removed default value for images # ... process images ... return {"Message": f" Album {name} created with {len[images]} images."}
The second issue is with the frontend JavaScript: only the first image file is being uploaded. This will cause an error because we’re sending a single file to the /new-album
endpoint that expects a list of files. To fix this change the code as follows:
function create_album() { var albumNameInput = document.getElementById('albumNameInput'); var imagesInput = document.getElementById('imagesInput'); var formData = new FormData(); formData.append('name', albumNameInput.value); for (const file of imagesInput.files) { // new for loop adds all files to images list formData.append('images', file); } fetch('/new-album', { method: 'POST', body: formData, }) .then(response => response.json()); } document.querySelector("form").addEventListener("submit", create_album);
When sending form data that includes files with JavaScript’s fetch
API, we should avoid manually setting the Content-Type
header, as this will prevent the browser from formatting the request correctly, per the documentation.
Loved by over 4 million developers and more than 90,000 organizations worldwide, Sentry provides code-level observability to many of the world’s best-known companies like Disney, Peloton, Cloudflare, Eventbrite, Slack, Supercell, and Rockstar Games. Each month we process billions of exceptions from the most popular products on the internet.