Uploading file with additional metadata in FastAPI — API and API clients
I recently worked on some Retrieval Augmented Generation (RAG) use cases to create an API endpoint to allow users to upload a file with some additional metadata like a user friendly name and description of the file, that could later be used to find the required documents and answer user’s queries.
The documentation here is quite elaborate and probably has all the details one might require to implement such an API in FastAPI. However, I found it slightly difficult to find the minimal code to implement a file upload with additional metadata. So here is my attempt at producing the minimal code which could be a decent starting point for an API designed to upload a file with additional metadata. The additional metadata in this case are the name and description of the file.
import shutil
from tempfile import NamedTemporaryFile
from typing import Annotated
import uvicorn
from fastapi import FastAPI, File, Form, HTTPException, UploadFile
app = FastAPI()
@app.post("/upload/")
async def upload_file(
file: Annotated[UploadFile, File()],
name: Annotated[str, Form()],
description: Annotated[str, Form()],
):
file_size = file.size
# max size of file is 10 MB
if file_size > 10 * 1024 * 1024:
raise HTTPException(status_code=413, detail="File size too large. Max size is 10 MB.")
print(f"file_size: {file_size} bytes")
file_metadata = {"name": name, "description": description}
print(f"file_metadata: {file_metadata}")
print(f"file_name: {file.filename}")
with NamedTemporaryFile(delete=False, suffix=".pdf") as temp_file:
shutil.copyfileobj(file.file, temp_file)
temp_file_path = temp_file.name # or store it in Azure blob/S3
# TODO: Pass the file path/object path to a worker e.g. in Celery or background task to further process the file
return {"message": "Files are being processed"}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
The UploadFile class has attributes and methods that are used in the above API implementation to get the file size, name and actual content.
Once the API is implemented, we can test the same with the below cURL request
curl --location '127.0.0.1:8000/upload/' \
--form 'file=@"/home/abc/def/faq-retail.pdf"' \
--form 'name="test"' \
--form 'user="user1"' \
--form 'description="FAQs"'
The following is a screenshot from Postman that makes the same request
We need to send the API parameters as form-data and not as JSON as mentioned in the thread here.
The same request when made using the Python requests library would look as the below:
import requests
url = 'http://127.0.0.1:8000/upload/'
files = {'file': open('/home/abc/def/faq-retail.pdf', 'rb')}
data = {'name': 'test', 'user': 'user1', 'description': 'FAQs'}
response = requests.post(url, files=files, data=data)
print(response.text)
Hope the above article helps you implement an API to upload files with parameters and then clients to use the API with the required file and metadata.