2

I have a FastAPI app with a download endpoint. What this download endpoint does is to use a BlobServiceClient (for Azure Blob Storage) to generate a token and a Blob URL to a file specified in the request. What I want to do is to redirect the user to that URL. Here is a code snippet of the download enpoint (I commented some things out because I'm not allowed to show the code).

@router.get("..path", tags=["some tags"], summary=..., responses={404: {"model": ...}, 403: {"model": ...}, 307: {"model": ...}}, response_model_exclude_none=True)
async def download_file(
        # there's a depends on an API key
        blob_path: str = Query(
            ...
        )):
credential = ClientSecretCredential(...)  //secrets
blob_service_client = BlobServiceClient(f"https://{storage_account}.blob.core.windows.net", credential=credential)
user_delegation_key = blob_service_client.get_user_delegation_key(key_start_time=datetime.utcnow(),key_expiry_time=datetime.utcnow() + timedelta(minutes=30))
    
token = generate_blob_sas(account_name=...,                                 
                          container_name=...,                                 
                          blob_name=blob_path,
                          user_delegation_key=user_delegation_key,
                          permission=BlobSasPermissions(read=True),
                          expiry=datetime.utcnow() + timedelta(minutes=30))
    
blob_url = f'https://{storage_account}.blob.core.windows.net/{container_name}/{blob_path}?{token}' 
print(blob_url)  
response = RedirectResponse(blob_url) 
return response

What I expected is the query to be executed, and after the response is returned, the download to start in the background or in a separate tab. What I've got instead is a different response as you can see in the Swagger:

enter image description here enter image description here

I also had a look in the Network tab to see what is happening with that request:

enter image description here enter image description here

Looks like there is an OPTIONS request and I assume that I'm getting the response to that request. Not sure if this is how Swagger handles the request. Any idea how/why this is happening and how to fix it? Thank you!

Chris
  • 18,724
  • 6
  • 46
  • 80
user14681827
  • 143
  • 1
  • 10
  • I understand what you are saying, the OPTIONS request returns a File response so that's why it is like that in Swagger. My question was why the OPTIONS request is done firstly (I assume because of the redirect) but why isn't that URL where I want to be redirected simply accessed (like when you click on an URL to download something and it starts downloading). Are you saying that redirect should not be followed? – user14681827 Sep 05 '22 at 10:39
  • What I am confused about is the functionality I'm trying to achieve which is accessing the URL and the OPTIONS request sent by Swagger to that URL – user14681827 Sep 05 '22 at 10:44

1 Answers1

2

To start with, the HTTP OPTIONS, in CORS, is a preflight request that is automatically issued by the browser, before the actual request—is not the one that returns the File response. It requests the permitted communication options for a given server, and the server responds with an Access-Control-Allow-Methods header including a set of permitted methods (e.g., Access-Control-Allow-Methods: OPTIONS, GET, HEAD, POST, DELETE). The preflight response can be optionally cached for the requests created in the same URL using Access-Control-Max-Age header, thus allowing the server to limit the number of preflight requests. The value of this header is expressed in seconds; hence, allowing caching for 10 minutes, for example, would look as Access-Control-Max-Age: 600.

As for the RedirectResponse, Swagger UI always follows redirect responses. In a fetch request, for instance, the redirect parameter would be set to follow, indicating that the redirect should be followed. This means that Swagger UI follows the redirect and waits for the response to be completely received before providing you with a Download file link (as shown in the screenshot you provided above) that would allow you to download the file. That is also why you can't see the download starting either in the background or in a new tab. As mentioned in the linked github post above, it is not possible to change that behaviour, which could allow you to handle it differently, similar to the approach demonstrated in this answer.

Instead of using Swagger UI to test that specific endpoint, you can either test it directly through typing the URL to your API endpoint in the address bar of your browser (since it is a GET endpoint, you can do that, as when you type a URL in the address bar of your browser, it performs a GET request), or create your own custom Template (or use HTMLResponse) and submit an HTML <form>, as shown in this answer.

Chris
  • 18,724
  • 6
  • 46
  • 80