How do I return an excel file (version: Office365) using FastAPI? The documentation seems pretty straightforward. But, I don't know what media_type
to use. Here's my code:
import os
from fastapi import FastAPI
from fastapi.responses import FileResponse
from pydantic import BaseModel
from typing import Optional
excel_file_path = r"C:\Users\some_path\the_excel_file.xlsx"
app = FastAPI()
class ExcelRequestInfo(BaseModel):
client_id: str
@app.post("/post_for_excel_file/")
async def serve_excel(item: ExcelRequestInfo):
# (Generate excel using item.)
# For now, return a fixed excel.
return FileResponse(
path=excel_file_path,
# Swagger UI says 'cannot render, look at console', but console shows nothing.
media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
# Swagger renders funny chars with this argument:
# 'application/vnd.ms-excel'
)
Assuming I get it right, how to download the file? Can I use Swagger UI generated by FastAPI to view the sheet? Or, curl? Ideally, I'd like to be able to download and view the file in Excel.
Solution
Here's my final (edited) solution to save you from clicking about. In the course of development, I had to switch from a FileResponse
to Response
that returns io.BytesIO
.
import io
import os.path
from fastapi.responses import Response
@router.get("/customer/{customer}/sheet")
async def generate_excel(customer: str):
excel_file_path: str = None
buffer: io.BytesIO = None
# Generate the sheet.
excel_file_path, buffer = make_excel(customer=customer)
# Return excel back to client.
headers = {
# By adding this, browsers can download this file.
'Content-Disposition': f'attachment; filename={os.path.basename(excel_file_path)}',
# Needed by our client readers, for CORS (cross origin resource sharing).
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "*",
"Access-Control_Allow-Methods": "POST, GET, OPTIONS",
}
media_type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
return Response(
content=buffer.getvalue(),
headers=headers,
media_type=media_type
)
You could set the Content-Disposition
header using the attachment
parameter, indicating to the web browser that the file should be downloaded, as described in the answers here and here. Swagger UI will provide a Download file
link for you to download the file, as soon as you execute the request.
headers = {'Content-Disposition': 'attachment; filename="Book.xlsx"'}
return FileResponse(excel_file_path, headers=headers)
To have the file viewed in the web browser, one can use the inline
, instead of attachment
, parameter in the Content-Disposition
header, as explained in the linked answers earlier. However, for the browser to be able to display the Excel file, one should set the correct media_type
in the FileResponse
(for Excel files see here), as well as .xlsx
(or .xls
) must be a known file extension to the browser (this is usually achieved through web browser extensions/plug-ins).