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
)