Download file using fastapi

Question:

I see the functions for uploading in an API, but I don’t see how to download. Am I missing something? I want to create an API for a file download site. Is there a different API I should be using?

from typing import List
from fastapi import FastAPI, Query

app = FastAPI()
PATH "some/path"

@app.get("/shows/")
    def get_items(q: List[str] = Query(None)):
        '''
        Pass path to function.
        Returns folders and files.
        '''
    
        results = {}
    
        query_items = {"q": q}
        entry = PATH + "/".join(query_items["q"]) + "/"

        dirs = os.listdir(entry)
        results["folders"] = [val for val in dirs if os.path.isdir(entry+val)]
        results["files"] = [val for val in dirs if os.path.isfile(entry+val)]
        results["path_vars"] = query_items["q"]
    
        return results

Here is the sample bit of code for python to fetch files and dirs for a path, you can return the path as a list with a new entry in a loop to go deeper into a file tree. Passing a file name should trigger a download function, but I cant seem to get a download func going.

Asked By: ScipioAfricanus

||

Answers:

I figured it out,

from starlette.responses import FileResponse
@app.get("/shows/")
    def get_items(q: List[str] = Query(None)):
    '''
    Pass path to function.
    Returns folders and files.
    '''

    results = {}

    query_items = {"q": q}
    if query_items["q"]:
        entry = PATH + "/".join(query_items["q"])
    else:
        entry = PATH

    if os.path.isfile(entry):
        return download(entry)

    dirs = os.listdir(entry + "/")
    results["folders"] = [
        val for val in dirs if os.path.isdir(entry + "/"+val)]
    results["files"] = [val for val in dirs if os.path.isfile(entry + "/"+val)]
    results["path_vars"] = query_items["q"]

    return results

def download(file_path):
    """
    Download file for given path.
    """
    if os.path.isfile(file_path):
        return FileResponse(file_path)
        # return FileResponse(path=file_path)
    return None

I added this part

from starlette.responses import FileResponse
if os.path.isfile(entry):
    return download(entry)

Allows you to host static file. But for some reason all files download as "download" .extension. If you know how to ensure original file name, let me know.

Answered By: ScipioAfricanus

This worked For me

from starlette.responses import FileResponse

return FileResponse(file_location, media_type='application/octet-stream',filename=file_name)

This will download the file with filename

Answered By: Avinash Ravi

Since we’re talking about FastAPI, the proper way to return a file response is covered in their documentation, code snippet below:

from fastapi import FastAPI
from fastapi.responses import FileResponse

file_path = "large-video-file.mp4"
app = FastAPI()

@app.get("/")
def main():
    return FileResponse(path=file_path, filename=file_path, media_type='text/mp4')
Answered By: Hamman Samuel

FastAPI uses Starlette’s FileResponse class so there are two ways to import FileResponse on your API code. But of course importing from FastAPI would be a better choice. You can follow the approach below to enable your API endpoints support file download.

Do not forget to add aiofiles to your dependency list. A basic requirements.txt file should look like (versions of modules might change in time, version 0.63.0 of fastapi strictly use starlette 0.13.6)

uvicorn==0.13.4
fastapi==0.63.0
starlette==0.13.6
aiofiles==0.6.0

And the API code

import os

from fastapi import FastAPI
from fastapi.responses import FileResponse


app = FastAPI()


@app.get("/")
async def main():
    file_name = "FILE NAME"
    # DEPENDS ON WHERE YOUR FILE LOCATES
    file_path = os.getcwd() + "/" + file_name
    return FileResponse(path=file_path, media_type='application/octet-stream', filename=file_name)
Answered By: abdullahselek

from fastapi import FastAPI
from fastapi.responses import FileResponse
import uvicorn
import os

app = FastAPI()

@app.get("/download-file")
def download_file(file_name: str):
folder_path = r"C:UsersHPDesktopexcel files"
file_location = f'{folder_path}{os.sep}{file_name}.xlsx’#os.sep is used to seperate with a
return FileResponse(file_location, media_type=’application/octet-stream’, filename=file_name)

uvicorn.run(app, port=9105)

Answered By: fathima
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.