본문 바로가기

개발하자

Download file using fastapi

반응형

Download file using fastapi

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.




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.




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




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')



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)



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:\Users\HP\Desktop\excel 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)


반응형