Create an Upload and Download Files API Endpoint with FastAPI

FastAPI is an awesome and simple framework for building APIs (application programming interfaces). Among the various features of FastAPI out of the box
we will be exploring how to include an endpoint whereby we can upload a json file and return another file that we can download.

In this tutorial we will create an endpoint for uploading and downloading files using FastAPI.
So what is the use case of this? In case you build a service where you want users to send a file format for processing eg json to yaml converter or json to latex or pdf convertion, understanding how to upload and download files with FastAPI will be helpful.

Let us start.

How to Upload Files in FastAPI


FastAPI provides a class object called UploadFile or Files for accepting file format via http request from an endpoint. For that to work you will need to install
python-multipart package for handling the upload feature via pip.
Below is the simple code

from fastapi import FastAPI, UploadFile
from fastapi.exceptions import HTTPException
import uvicorn 
import json

# Init App
app = FastAPI()

@app.post("/file/upload")
def upload_file(file: UploadFile):
    if file.content_type != "application/json":
        raise HTTPException(400,detail="Invalid document type")
    else:
        data = json.loads(file.file.read())
    return {"content":data ,"filename":file.filename}


if __name__ == '__main__':
    uvicorn.run(app,host="127.0.0.1",port=8000)

How to Create an Endpoint for Downloading Files


With FastAPI FileResponse object, you can return files via your HTTP response.
The recommended way is to save the file in a directory and transmitting via the FileResponse class object as below.

@app.post("/file/uploadndownload")
def upload_n_downloadfile(file: UploadFile):
    """Return a YAML FIle for the uploaded JSON File"""
    if file.content_type != "application/json":
        raise HTTPException(400,detail="Invalid document type")
    else:
        json_data = json.loads(file.file.read())
        new_filename = "{}_{}.yaml".format(os.path.splitext(file.filename)[0],timestr)
        # Write the data to a file
        # Store the saved file
        SAVE_FILE_PATH = os.path.join(UPLOAD_DIR,new_filename)
        with open(SAVE_FILE_PATH,"w") as f:
            yaml.dump(json_data,f)

        # Return as a download
        return FileResponse(path=SAVE_FILE_PATH,media_type="application/octet-stream",filename=new_filename)

We are using a media_type or mime type of application/octet-stream since this support multiple file types or mime types.

Now let us combine the two into building a service to upload JSON files and return a valid YAML File for download.

Full Code for download and upload
import time
from fastapi import FastAPI, UploadFile
from fastapi.exceptions import HTTPException
from fastapi.responses import FileResponse
import uvicorn
import json
import os
import yaml


app = FastAPI()

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
UPLOAD_DIR = os.path.join(BASE_DIR, "uploads")
timestr = time.strftime("%Y%m%d-%H%M%S")

@app.get("/")
def read_root():
    return {"Hello": "FastAPI"}


@app.post("/file/upload")
def upload_file(file: UploadFile):
    if file.content_type != "application/json":
        raise HTTPException(400, detail="Invalid document type")
    else:
        data = json.loads(file.file.read())
    return {"content": data, "filename": file.filename}


@app.post("/file/uploadndownload")
def upload_n_downloadfile(file: UploadFile):
    """Return a YAML FIle for the uploaded JSON File"""
    if file.content_type != "application/json":
        raise HTTPException(400, detail="Invalid document type")
    else:
        json_data = json.loads(file.file.read())
        new_filename = "{}_{}.yaml".format(os.path.splitext(file.filename)[0], timestr)
        # Write the data to a file
        # Store the saved file
        SAVE_FILE_PATH = os.path.join(UPLOAD_DIR, new_filename)
        with open(SAVE_FILE_PATH, "w") as f:
            yaml.dump(json_data, f)

        # Return as a download
        return FileResponse(
            path=SAVE_FILE_PATH,
            media_type="application/octet-stream",
            filename=new_filename,
        )


if __name__ == "__main__":
    uvicorn.run(app, host="127.0.0.1", port=8000)

You can check out the video tutorial for more

Thank You For Your Time
Jesus Saves @ JCharisTech


By Jesse E.Agbe

Leave a Comment

Your email address will not be published. Required fields are marked *