'FastAPI/Mangum JSON decode error when uploading multiple files

I'm trying to create a serverless file upload API using FastAPI/Mangum and am running into a strange JSON decoding issue when attempting to follow the example in the docs. Here is my code

# main.py
import os

from typing import List
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import HTMLResponse
from mangum import Mangum

app = FastAPI()

@app.get("/")
async def main():
    content = """
    <body>
     <form action="/registration/create" enctype="multipart/form-data" method="post">
      <input name="files" type="file" multiple>
      <input type="submit">
     </form>
    </body>
    """
    return HTMLResponse(content=content)

@app.post("/registration/create")
async def create_registration(files: List[UploadFile]):
    return {"file_len": len(files)}

handler = Mangum(app)
# test_main.py
from urllib import response
from fastapi.testclient import TestClient
from main import app

client = TestClient(app)

def test_registration():
    files = [('files', ('example.txt', open('example.txt', 'rb'), 'text/plain'))]
    response = client.post("/registration/create", files=files)
    assert response.status_code == 200

When I run the test or attempt to post files using the web page example I receive a JSON decoding error and the request fails with 422:

{
 "detail":
   [{"loc":["body",0],
     "msg":"Expecting value: line 1 column 1 (char 0)",
     "type":"value_error.jsondecode",
     "ctx": {
       "msg": "Expecting value",
       "doc": "\nContent-Disposition: form-data; name=\\"files\\"; filename=\\"example.txt\\"\\r\\nContent-Type: text/plain\\r\\n\\r\\nexample text in the file\n",
     "pos":0,
     "lineno":1,
     "colno":1
  }
 }]
}

Here is the docs page I am referencing: https://fastapi.tiangolo.com/tutorial/request-files/#multiple-file-uploads



Solution 1:[1]

You should define the files parameter as shown below. Also, "file_len": len(files) would return the number of files received, not the file length of each file in the List. To do that, you should loop through the list of files and find the length of each file (after reading the contents of each file), as shown below. Please take a look at the documentation as well.

async def create_registration(files: List[UploadFile] = File(...)):
    return {"file_sizes": [len(await file.read()) for file in files]}

or, have FastAPI read the contents for you, by declaring the type of your parameter as bytes.

async def create_registration(files: List[bytes] = File(...)):
    return {"file_sizes": [len(file) for file in files]}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1