4

My app uses React on the frontend and FastAPI on the backend.

I'm trying to upload a csv file to my server.

On submitting a form, this gets called:

  const onSubmit = async (e) => {
    e.preventDefault();
    const formData = new FormData();
    formData.append("file", file);
    fetch("/api/textitems/upload", {
      method: "POST",
      body: formData,
    });
  };

The data is received by:

@app.post('/api/textitems/upload')
def upload_file(csv_file: UploadFile = File(...)):
    dataframe = pd.read_csv(csv_file.file)
    return dataframe.head()

I keep getting INFO: 127.0.0.1:0 - "POST /api/textitems/upload HTTP/1.1" 422 Unprocessable Entity errors.

I am able to successfully perform the post request with curl like so:

curl -X POST "http://localhost:8000/api/textitems/upload" -H "accept: application/json" -H "Content-Type: multipart/form-data" -F "csv_file=@exp_prod.csv;type=text/csv"

Any advice about where I'm going wrong when using Javascript though?

Henry Dashwood
  • 143
  • 1
  • 2
  • 13
  • Do you have `python-multipart` installed on your current environment? – Yagiz Degirmenci Aug 06 '20 at 23:19
  • Yes I do have `python-multipart` – Henry Dashwood Aug 06 '20 at 23:21
  • I think your returning value causes this, by default fastapi expects key:value pairs, i'm not sure how `head()` sends data but can you try with dict? Also there was a function like `to_dict()` in pandas or something else and `FileResponse` from `fastapi.responses` could be helpful. – Yagiz Degirmenci Aug 06 '20 at 23:28
  • I've tried but unfortunately without success. I'm fairly sure it's that JS's fetch method is not sending something that FastAPI considers a correct type. I believe this because the endpoint does not even run when the input comes from my frontend yet it returns the desired output when invoked using curl. – Henry Dashwood Aug 06 '20 at 23:40

3 Answers3

2

I did eventually solve this. Isabi's answer helped me, as did learning about FormData's append method. Here are the working code snippets in case anyone finds them useful.

  const onSubmit = async (e) => {
    e.preventDefault();
    const formData = new FormData();
    formData.append("file", file, file.name);
    await fetch(`/api/textitems/upload`, {
      method: "POST",
      body: formData,
    })
@app.post('/api/textitems/upload')
def upload_file(file: UploadFile = File(...), db: Session = Depends(get_db)):
    df = pd.read_csv(file.file).head()
    return df
Henry Dashwood
  • 143
  • 1
  • 2
  • 13
1

Be sure that the name of the file in the form matches the name of the file in the parameter!

See my answer to the same question below.

How to send file to fastapi endpoint using postman

lsabi
  • 3,641
  • 1
  • 14
  • 26
0

Set Content-Type header to multipart/form-data on your request:

  const onSubmit = async (e) => {
    e.preventDefault();
    const formData = new FormData();
    formData.append("file", file);
    fetch("/api/textitems/upload", {
      method: "POST",
      body: formData,
      headers: {
          'Content-Type': 'multipart/form-data',
      }
    });
  };
Gabriel Cappelli
  • 3,632
  • 1
  • 17
  • 31