Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to have the dialog box for choosing download location appeared in the frontend, before the file gets downloaded, using FastAPI?

I have a GET endpoint that should return a huge file (500Mb). I am using FileResponse to do that (the code is simplified for clarity reasons):

 async def get_file()
       headers = {"Content-Disposition": f"attachment; filename={filename}"}
       return FileResponse(file_path, headers=headers)

The problem is that I have to wait on the frontend until that file is completely downloaded, in order for the dialog box that allows choosing a download location to be shown: enter image description here

And then, this file is saved instantly.

So, for example, I have a file with size 500 MB, when I click download on UI I have to wait a minute or something till the "Save dialog" is displayed. Then, when I click "Save" the file is saved instantly. Obviously, the frontend was waiting for the file to be downloaded.

What I need is: The dialog to be shown instantly and then the user waiting for the file downloading to finish, after the user clicks 'Save' to choose the download location. So, how can I achieve that?

like image 960
unresolved_external Avatar asked Dec 05 '25 13:12

unresolved_external


1 Answers

Problem Overview

You haven't provided any details, regarding the client side of your project, but it seems that the client is most likely requesting the resource (file) using an asynchronous JavaScript request, such as fetch() request. If you are using Swagger UI autodocs for testing your application, it also uses the Fetch API behind the scenes—see this answer.

When requesting such a large file (500 MB), or any resource, using fetch() or any other asynchronous JavaScript library (as demonstrated in this answer, as well as this answer and this answer), the response from the server has to be completely received, before further proceeding with showing the dialog box/window to choose the location, where you would like the file to be downloaded (see the linked answer provided earlier for the Swagger UI case).

Hence, instead of using JavaScript to request the resource, you could achieve having the dialog box for choosing the download location showed up beforehand, using the following approach.

Solution

Backend

Setting the filename argument of FileResponse, for example:

return FileResponse(file_path, filename="BigFile.zip")

would add the Content-Disposition response header with the attachment flag, indicating that the file should be downloaded instead of viewed in the browser. If, however, you would like to be certain about it, you could add the Content-Disposition header to the response on your own, as demonstrated here and here, and as shown below:

@app.get("/download")
def download_file():
    file_path = "files/BigFile.zip"
    headers = {'Content-Disposition': 'attachment; filename="BigFile.zip"'}
    return FileResponse(file_path, headers=headers)

Frontend

On the frontend, you could simply use a hyperlink, defined by the <a> tag:

<a href="/download">Download</a>

In case the backend did not set the Content-Disposition response header with the attachment flag included, you could use the download attribute in the hyperlink on the frontend, which "specifies that the target (the file specified in the href attribute) will be downloaded when a user clicks on the hyperlink" (see related w3schools article):

<a href="/download" download>Download</a>

Using a <button> instead of <a> hyperlink

If you needed having the user to click on a button instead of a hyperlink, you could use one of the following:

<button>
<a href="/download" style="text-decoration: none; color: unset; cursor: default;" download>Download</a>
</button>

or

<button onclick="document.getElementById('my_link').click()">Download</button>
<a id="my_link" href="/download" download hidden></a>

or

<form method="get" action="/download">
 <button type="submit">Download</button>
</form>

or

<button type="submit" onclick="window.location.href='/download'">Download</button>

Note: In the case of the last two options above, remember to set the Content-Disposition response header with the attachment flag on server side, so that the file gets downloaded instead of viewed in the browser, as you can't add the <a> hyperlink download attribute in those cases.

Initiate the file download through JavaScript

If you needed to initiate/trigger the file download through a JavaScript function, you could use the below. The <button> element below is optional; you could remove it, if you don't need the user to click on a button, but, instead, would like to automatically trigger the file downloading through a JS function.

<a id="my_link" href="/download" download hidden></a>
<button onClick="downloadFile()">Download</button>
<script>
   function downloadFile() {
     document.getElementById("my_link").click()
   }
</script>
like image 69
Chris Avatar answered Dec 08 '25 09:12

Chris