pythonfile-uploadpostmanfastapihttp-status-code-422

FastAPI raises 422 Unprocessable Entity error when uploading File through Postman


I am using a POST request for uploading a file to a FastAPI application through Postman, and save it to my local directory. However, a 422 (Unprocessable entity) error is raised, saying that the file is missing. I selected the binary option to upload the file, as can be seen in the image below:

enter image description here

Below is how my FastAPI backend looks like:

main.py

from fastapi import FastAPI
from api.endpoints.vendor import router

app = FastAPI(title='Vendor Acknolegment API')
app.include_router(router, prefix='/vendor', tags=['vendor confirmation'])

if __name__ == '__main__':
    import uvicorn
    uvicorn.run("main:app", host="0.0.0.0", port=8000, log_level='info', reload=True)

vendor.py

from fastapi import APIRouter, status, File, UploadFile
#from lxml import etree
import os

# file path
UPLOAD_DIR = r"c:\ack"

# check if the directory exists.
os.makedirs(UPLOAD_DIR, exist_ok=True)

# creates the endpoint path
router = APIRouter()

# POST Ack
@router.post("/ack/", status_code=status.HTTP_201_CREATED)
async def upload_ack(file: UploadFile = File(...)):
    # define the complete path where the file will be saved.
    file_location = os.path.join(UPLOAD_DIR, file.filename)

    with open(file_location, "wb") as f:
        f.write(await file.read())

    return {"message": f"The file '{file.filename}' has been successfully saved into the server."}

Solution

  • Option 1

    As described in this answer, and demonstrated in this answer as well, when using FastAPI/Starlette's UploadFile (you might want to have a look at Starlette's documentation on UploadFile too), files are uploaded as multipart/form-data. Example of how the backend should look like can be found below:

    from fastapi import File, UploadFile
    
    @app.post("/upload")
    async def upload(file: UploadFile = File(...)):
        pass
    

    Hence, in Postman, you should select Body -> form-data and enter the key (i.e., parameter name) given for the UploadFile object in your API endpoint—in your case and the example above, that is file, since the parameter is defined as file: UploadFile = File(...)—then select File from the drop-down menu next to the key you just entered in Postman, and finally, upload your file in the Value section by clicking on the Select files button. In case of uploading multiple files, e.g., files: List[UploadFile] = File(...), the key should then be files, for instance.

    Option 2

    Instead, if you would like to use the binary option in Postman to upload a file, as shown in your question (i.e., Body -> binary)—which would result in significantly better performance (especially, when you expect users to upload rather large files), not because of Postman, but due to how faster the uploading of file(s) becomes when processing the byte chunks as they arrive using FastAPI/Starlette's request.stream() compared to using UploadFile (more details are given in the linked answers below)—then, in that case, please have a look at this answer (see the Update section) and this answer on how you should have the API endpoint implemented in your backend.