I have some issue with using Fetch API JavaScript method when sending some simple formData
like so:
function register() {
var formData = new FormData();
var textInputName = document.getElementById('textInputName');
var sexButtonActive = document.querySelector('#buttonsMW > .btn.active');
var imagesInput = document.getElementById('imagesInput');
formData.append('name', textInputName.value);
if (sexButtonActive != null){
formData.append('sex', sexButtonActive.html())
} else {
formData.append('sex', "");
}
formData.append('images', imagesInput.files[0]);
fetch('/user/register', {
method: 'POST',
data: formData,
})
.then(response => response.json());
}
document.querySelector("form").addEventListener("submit", register);
And on the server side (FastAPI):
@app.post("/user/register", status_code=201)
def register_user(name: str = Form(...), sex: str = Form(...), images: List[UploadFile] = Form(...)):
try:
print(name)
print(sex)
print(images)
return "OK"
except Exception as err:
print(err)
print(traceback.format_exc())
return "Error"
After clicking on the submit button I get Error 422: Unprocessable entity
. So, if I'm trying to add header Content-Type: multipart/form-data
, it also doesn't help cause I get another Error 400: Bad Request
. I want to understand what I am doing wrong, and how to process formData
without such errors?
The 422
error response body will contain an error message about which field(s) is missing or doesn’t match the expected format. Since you haven't provided that (please do so), my guess is that the error is triggered due to how you defined the images
parameter in your endpoint. Since images
is expected to be a List
of File
(s), you should instead define it using the File
type instead of Form
. For example:
images: List[UploadFile] = File(...)
^^^^
When using UploadFile
, you don't have to use File()
in the default value of the parameter, meaning that the below should work as well:
images: List[UploadFile]
Hence, the FastAPI endpoint should look similar to this:
@app.post("/user/register")
async def register_user(name: str = Form(...), images: List[UploadFile] = File(...)):
pass
In the frontend, make sure to use the body
(not data
) parameter in the fetch()
function to pass the FormData
object (see example in MDN Web Docs). For instance:
var nameInput = document.getElementById('nameInput');
var imagesInput = document.getElementById('imagesInput');
var formData = new FormData();
formData.append('name', nameInput.value);
for (const file of imagesInput.files)
formData.append('images', file);
fetch('/user/register', {
method: 'POST',
body: formData,
})
.then(response => {
console.log(response);
})
.catch(error => {
console.error(error);
});
Please have a look at this answer, as well as this answer, which provide working examples on how to upload multiple files
and form
data to a FastAPI backend, using Fetch API in the frontend.
As for manually specifying the Content-Type
when sending multipart/form-data
, you don't have to (and shouldn't) do that, but rather let the browser set the Content-Type
—please take a look at this answer for more details.