3

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?

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for your answer, after reading your proof links I found the right solution (wrote below).
Thanks for the answer, I was having a similar problem and removed the header on my request where I manually added the Content-Type and it solved my 422 error (despite adding the same Content-Type header).
0

So, I found that I has error in this part of code:

formData.append('images', imagesInput.files[0]);

Right way to upload multiple files is:

for (const image of imagesInput.files) {
    formData.append('images', image);
}

Also, we should use File in FastAPI method arguments images: List[UploadFile] = File(...) (instead of Form) and change data to body in JS method. It's not an error, cause after method called, we get right type of data, for example:

Name: Bob
Sex: Man
Images: [<starlette.datastructures.UploadFile object at 0x7fe07abf04f0>]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.