Download PDF file using pdfkit and FastAPI
Question:
I am going to create an API that converts an HTML
page to a PDF file. I made it using pdfkit
and FastAPI
. However, it saves the file to my local disk. After I serve this API online, how could users download this PDF file to their computer?
from typing import Optional
from fastapi import FastAPI
import pdfkit
app = FastAPI()
@app.post("/htmltopdf/{url}")
def convert_url(url:str):
pdfkit.from_url(url, 'converted.pdf')
Answers:
Returning FileResponse is solved my problem. Thanks to @Paul H and @clmno
Below codes are working example of returning pdf file to download with FastApi.
from typing import Optional
from fastapi import FastAPI
from starlette.responses import FileResponse
import pdfkit
app = FastAPI()
config = pdfkit.configuration(wkhtmltopdf=r"C:Program Fileswkhtmltopdfbinwkhtmltopdf.exe")
@app.get("/")
def read_root():
pdfkit.from_url("https://nakhal.expo.com.tr/nakhal/preview","file.pdf", configuration=config)
return FileResponse(
"file.pdf",
media_type="application/pdf",
filename="ticket.pdf")
**2)**This is another way with using tempfiles – to add pdf to a variable just write False instead of path –
from typing import Optional
from fastapi import FastAPI
from starlette.responses import FileResponse
import tempfile
import pdfkit
app = FastAPI()
config = pdfkit.configuration(wkhtmltopdf=r"C:Program Fileswkhtmltopdfbinwkhtmltopdf.exe")
@app.get("/")
def read_root():
pdf = pdfkit.from_url("https://nakhal.expo.com.tr/nakhal/preview",False, configuration=config)
with tempfile.NamedTemporaryFile(mode="w+b", suffix=".pdf", delete=False) as TPDF:
TPDF.write(pdf)
return FileResponse(
TPDF.name,
media_type="application/pdf",
filename="ticket.pdf")
Once you get the bytes
of the PDF file, you can simply return a custom Response
, specifying the content
, headers
and media_type
. Thus, no need for saving the file to the disk or generating temporary files, as suggested by another answer. Similar to this answer, you can set the Content-Disposition
header to let the browser know whether the PDF file should be viewed or downloaded.
Example
from fastapi import Response
import pdfkit
config = pdfkit.configuration(wkhtmltopdf=r'YOUR_DIR_TO/wkhtmltopdf/bin/wkhtmltopdf.exe')
@app.get('/')
def main():
pdf = pdfkit.from_url('http://google.com', configuration=config)
headers = {'Content-Disposition': 'attachment; filename="out.pdf"'}
return Response(pdf, headers=headers, media_type='application/pdf')
To have the PDF file viewed in the borwser instead of downloaded, use:
headers = {'Content-Disposition': 'inline; filename="out.pdf"'}
See this answer on how to install and use pdfkit.
I am going to create an API that converts an HTML
page to a PDF file. I made it using pdfkit
and FastAPI
. However, it saves the file to my local disk. After I serve this API online, how could users download this PDF file to their computer?
from typing import Optional
from fastapi import FastAPI
import pdfkit
app = FastAPI()
@app.post("/htmltopdf/{url}")
def convert_url(url:str):
pdfkit.from_url(url, 'converted.pdf')
Returning FileResponse is solved my problem. Thanks to @Paul H and @clmno
Below codes are working example of returning pdf file to download with FastApi.
from typing import Optional
from fastapi import FastAPI
from starlette.responses import FileResponse
import pdfkit
app = FastAPI()
config = pdfkit.configuration(wkhtmltopdf=r"C:Program Fileswkhtmltopdfbinwkhtmltopdf.exe")
@app.get("/")
def read_root():
pdfkit.from_url("https://nakhal.expo.com.tr/nakhal/preview","file.pdf", configuration=config)
return FileResponse(
"file.pdf",
media_type="application/pdf",
filename="ticket.pdf")
**2)**This is another way with using tempfiles – to add pdf to a variable just write False instead of path –
from typing import Optional
from fastapi import FastAPI
from starlette.responses import FileResponse
import tempfile
import pdfkit
app = FastAPI()
config = pdfkit.configuration(wkhtmltopdf=r"C:Program Fileswkhtmltopdfbinwkhtmltopdf.exe")
@app.get("/")
def read_root():
pdf = pdfkit.from_url("https://nakhal.expo.com.tr/nakhal/preview",False, configuration=config)
with tempfile.NamedTemporaryFile(mode="w+b", suffix=".pdf", delete=False) as TPDF:
TPDF.write(pdf)
return FileResponse(
TPDF.name,
media_type="application/pdf",
filename="ticket.pdf")
Once you get the bytes
of the PDF file, you can simply return a custom Response
, specifying the content
, headers
and media_type
. Thus, no need for saving the file to the disk or generating temporary files, as suggested by another answer. Similar to this answer, you can set the Content-Disposition
header to let the browser know whether the PDF file should be viewed or downloaded.
Example
from fastapi import Response
import pdfkit
config = pdfkit.configuration(wkhtmltopdf=r'YOUR_DIR_TO/wkhtmltopdf/bin/wkhtmltopdf.exe')
@app.get('/')
def main():
pdf = pdfkit.from_url('http://google.com', configuration=config)
headers = {'Content-Disposition': 'attachment; filename="out.pdf"'}
return Response(pdf, headers=headers, media_type='application/pdf')
To have the PDF file viewed in the borwser instead of downloaded, use:
headers = {'Content-Disposition': 'inline; filename="out.pdf"'}
See this answer on how to install and use pdfkit.