fpdf2 - Usage in web APIs (original) (raw)
Note that FPDF
instance objects are not designed to be reusable: content cannot be added once output() has been called.
Hence, even if the FPDF
class should be thread-safe, we recommend that you either create an instance for every request, or if you want to use a global / shared object, to only store the bytes returned from output()
.
Django¶
Django is:
a high-level Python web framework that encourages rapid development and clean, pragmatic design
There is how you can return a PDF document from a Django view:
`from django.http import HttpResponse from fpdf import FPDF
def report(request): pdf = FPDF() pdf.add_page() pdf.set_font("Helvetica", size=24) pdf.cell(text="hello world") return HttpResponse(bytes(pdf.output()), content_type="application/pdf") `
Flask¶
Flask is a micro web framework written in Python.
The following code can be placed in a app.py
file and launched using flask run
:
`from flask import Flask, make_response from fpdf import FPDF
app = Flask(name)
@app.route("/") def hello_world(): pdf = FPDF() pdf.add_page() pdf.set_font("Helvetica", size=24) pdf.cell(text="hello world") response = make_response(bytes(pdf.output())) response.headers["Content-Type"] = "application/pdf" return response `
gunicorn¶
Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX.
The following code can be placed in a gunicorn_fpdf2.py
file and launched using gunicorn -w 4 gunicorn_fpdf2:app
:
`from fpdf import FPDF
def app(environ, start_response): pdf = FPDF() pdf.add_page() pdf.set_font("Helvetica", size=12) pdf.cell(text="Hello world!") data = bytes(pdf.output()) start_response("200 OK", [ ("Content-Type", "application/pdf"), ("Content-Length", str(len(data))) ]) return iter([data]) `
AWS lambda¶
The following code demonstrates some minimal AWS lambda handler function that returns a PDF file as binary output:
`from base64 import b64encode from fpdf import FPDF
def handler(event, context): pdf = FPDF() pdf.add_page() pdf.set_font("Helvetica", size=24) pdf.cell(text="hello world") return { 'statusCode': 200, 'headers': { 'Content-Type': 'application/json', }, 'body': b64encode(pdf.output()).decode('utf-8'), 'isBase64Encoded': True } `
This AWS lambda function can then be linked to a HTTP endpoint using API Gateway, or simply exposed as a Lambda Function URL. More information on those pages:
For reference, the test lambda function was initiated using the following AWS CLI commands:
Creating & uploading a lambda layer
`pyv=3.8 pip${pyv} install fpdf2 -t python/lib/python${pyv}/site-packages/
We use a distinct layer for Pillow:
rm -r python/lib/python${pyv}/site-packages/{PIL,Pillow}*
zip -r fpdf2-deps.zip python > /dev/null
aws lambda publish-layer-version --layer-name fpdf2-deps
--description "Dependencies for fpdf2 lambda"
--zip-file fileb://fpdf2-deps.zip --compatible-runtimes python${pyv}
`
Creating the lambda
AWS_ACCOUNT_ID=... AWS_REGION=eu-west-3 zip -r fpdf2-test.zip lambda.py aws lambda create-function --function-name fpdf2-test --runtime python${pyv} \ --zip-file fileb://fpdf2-test.zip --handler lambda.handler \ --role arn:aws:iam::${AWS_ACCOUNT_ID}:role/lambda-fpdf2-role \ --layers arn:aws:lambda:${AWS_REGION}:770693421928:layer:Klayers-python${pyv/./}-Pillow:15 \ arn:aws:lambda:${AWS_REGION}:${AWS_ACCOUNT_ID}:layer:fpdf2-deps:1 aws lambda create-function-url-config --function-name fpdf2-test --auth-type NONE
Those commands do not cover the creation of the lambda-fpdf2-role
role, nor configuring the lambda access permissions, for example with a FunctionURLAllowPublicAccess
resource-based policy.
streamlit¶
streamlit is:
a Python library that makes it easy to create and share custom web apps for data science
The following code demonstrates how to display a PDF and add a button allowing to download it:
`from base64 import b64encode from fpdf import FPDF import streamlit as st
st.title("Demo of fpdf2 usage with streamlit")
@st.cache def gen_pdf(): pdf = FPDF() pdf.add_page() pdf.set_font("Helvetica", size=24) pdf.cell(text="hello world") return bytes(pdf.output())
Embed PDF to display it:
base64_pdf = b64encode(gen_pdf()).decode("utf-8") pdf_display = f'' st.markdown(pdf_display, unsafe_allow_html=True)
Add a download button:
st.download_button( label="Download PDF", data=gen_pdf(), file_name="file_name.pdf", mime="application/pdf", ) `
FastAPI¶
FastAPI is:
a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints.
The following code shows how to generate a PDF file via a POST endpoint that receives a JSON object. The JSON object can be used to write into the PDF file. The generated PDF file will be returned back to the user/frontend as the response.
`from fastapi import FastAPI, Request, Response, HTTPException, status from fpdf import FPDF
app = FastAPI()
@app.post("/send_data", status_code=status.HTTP_200_OK) async def create_pdf(request: Request): """ POST endpoint that accepts a JSON object This endpoint returns a PDF file as the response """ try: # data will read the JSON object and can be accessed like a Python Dictionary # The contents of the JSON object can be used to write into the PDF file (if needed) data = await request.json()
# Create a sample PDF file
pdf = FPDF()
pdf.add_page()
pdf.set_font("Helvetica", size=24)
pdf.cell(text="hello world")
# pdf.cell(text=data["content"]) # Using the contents of the JSON object to write into the PDF file
# Use str(data["content"]) if the content is non-string type
# Prepare the filename and headers
filename = "<file_name_here>.pdf"
headers = {
"Content-Disposition": f"attachment; filename={filename}"
}
# Return the file as a response
return Response(content=bytes(pdf.output()), media_type="application/pdf", headers=headers)
except Exception as e:
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
`
Jupyter¶
Check tutorial/notebook.ipynb
web2py¶
Usage of the original PyFPDF lib with web2py is described here: https://github.com/reingart/pyfpdf/blob/master/docs/Web2Py.md
v1.7.2
of PyFPDF is included in web2py
since release 1.85.2
: https://github.com/web2py/web2py/tree/master/gluon/contrib/fpdf