-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
50 lines (42 loc) · 1.94 KB
/
app.py
File metadata and controls
50 lines (42 loc) · 1.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# app.py
# FastAPI service that converts HTML to PDF using Playwright (Chromium).
# Auth: Bearer token via RENDERER_TOKEN env var.
import os
import base64
from fastapi import FastAPI, Header, HTTPException
from pydantic import BaseModel
from playwright.sync_api import sync_playwright
APP = FastAPI(title="PDF Renderer", version="1.0.0")
RENDERER_TOKEN = os.getenv("RENDERER_TOKEN") # set in Heroku Config Vars
class Payload(BaseModel):
html: str
header: str | None = None # optional HTML for header template
footer: str | None = None # optional HTML for footer template
format: str = "A4" # e.g., "A4" or "Letter"
def _require_bearer(authorization: str | None):
if not RENDERER_TOKEN:
# If you forget to set the token, refuse to start/publicize
raise RuntimeError("RENDERER_TOKEN is not set")
if not authorization or not authorization.startswith("Bearer "):
raise HTTPException(401, "Missing or invalid Authorization")
token = authorization.split(" ", 1)[1]
if token != RENDERER_TOKEN:
raise HTTPException(403, "Forbidden")
@APP.post("/render")
def render(payload: Payload, authorization: str | None = Header(default=None)):
_require_bearer(authorization)
with sync_playwright() as p:
browser = p.chromium.launch(args=["--no-sandbox"])
page = browser.new_page()
page.set_content(payload.html, wait_until="networkidle")
pdf = page.pdf(
format=payload.format,
print_background=True,
display_header_footer=bool(payload.header or payload.footer),
header_template=payload.header or "<div></div>",
footer_template=payload.footer or "<div></div>",
margin={"top": "18mm", "bottom": "18mm", "left": "15mm", "right": "15mm"},
)
browser.close()
# Return base64 to avoid content-type proxying issues and keep it simple
return {"pdf_base64": base64.b64encode(pdf).decode("ascii")}