Vamos a montar un microservicio con FastAPI que reciba datos y genere PDFs a partir de plantillas HTML. Este endpoint te servirá para cualquier necesidad de generación de documentos en tu infraestructura.
Requisitos Previos
- Python 3.7+
pip(gestor de paquetes de Python)- Un editor de texto o IDE
Pasos para Crear el Generador de PDFs
1. Configurar el Entorno Virtual e Instalar Dependencias
Es una buena práctica aislar las dependencias de tu proyecto. Crea un entorno virtual y luego instala FastAPI, Uvicorn (servidor ASGI) y weasyprint (para la conversión HTML a PDF).
python -m venv venv
source venv/bin/activate # En Windows usa `venv\Scripts\activate`
pip install fastapi uvicorn weasyprint
2. Crear la Plantilla HTML
Vamos a usar una plantilla HTML simple. Crea un archivo llamado template.html en un directorio templates.
<!DOCTYPE html>
<html>
<head>
<title>Reporte: {{ title }}</title>
<style>
body { font-family: sans-serif; }
.container { margin: 20px; }
h1 { color: #333; }
.data-item {
margin-bottom: 10px;
border-bottom: 1px solid #eee;
padding-bottom: 5px;
}
.data-item strong {
display: inline-block;
width: 100px;
}
</style>
</head>
<body>
<div class="container">
<h1>{{ title }}</h1>
{% for item in data %}
<div class="data-item">
<strong>{{ item.key }}:</strong> {{ item.value }}
</div>
{% endfor %}
</div>
</body>
</html>
3. Desarrollar la Aplicación FastAPI
Crea un archivo main.py. Este script definirá un endpoint que recibe datos en formato JSON, los renderiza en la plantilla HTML y luego los convierte a PDF.
from fastapi import FastAPI, HTTPException
from fastapi.responses import StreamingResponse
from weasyprint import HTML
from jinja2 import Environment, FileSystemLoader
import io
import json
app = FastAPI()
# Configurar Jinja2 para cargar plantillas
# Asegúrate de que la carpeta 'templates' existe en el mismo directorio que main.py
file_loader = FileSystemLoader('templates')
env = Environment(loader=file_loader)
@app.post("/generate-pdf/")
def generate_pdf(payload: dict):
"""
Genera un archivo PDF a partir de una plantilla HTML y datos proporcionados.
Args:
payload: Un diccionario que debe contener:
"template_name": El nombre del archivo de plantilla HTML (ej: "template.html").
"context": Un diccionario con los datos para renderizar en la plantilla.
"""
template_name = payload.get("template_name")
context = payload.get("context", {{}})
if not template_name:
raise HTTPException(status_code=400, detail="Missing 'template_name' in payload")
try:
template = env.get_template(template_name)
html_content = template.render(context)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error rendering template: {str(e)}")
try:
# Generar PDF en memoria
pdf_bytes = HTML(string=html_content).write_pdf()
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error generating PDF: {str(e)}")
# Devolver el PDF como un stream
pdf_stream = io.BytesIO(pdf_bytes)
return StreamingResponse(pdf_stream, media_type="application/pdf", headers={
"Content-Disposition": f"attachment; filename={template_name.replace('.html', '.pdf')}"
})
@app.get("/")
def read_root():
return {"message": "PDF Generator API is running. POST to /generate-pdf/ with template_name and context."}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
4. Ejecutar el Servicio
Inicia el servidor Uvicorn desde tu terminal.
uvicorn main:app --reload
Ahora tu API estará disponible en http://127.0.0.1:8000. Puedes usar curl o herramientas como Postman para probarla.
Ejemplo de Llamada con curl
curl -X POST "http://127.0.0.1:8000/generate-pdf/" \
-H "Content-Type: application/json" \
-d '{
"template_name": "template.html",
"context": {
"title": "Reporte de Ventas Semanal",
"data": [
{"key": "Producto A", "value": "150 unidades"},
{"key": "Producto B", "value": "210 unidades"},
{"key": "Producto C", "value": "95 unidades"}
]
}
}' \
--output reporte.pdf
Esto creará un archivo reporte.pdf en tu directorio actual.
Consejo Pro: Manejo de Errores y Configuraciones Avanzadas
weasyprint tiene muchas opciones para controlar CSS, fuentes y márgenes. Consulta su documentación para personalizaciones avanzadas. Para producción, considera usar un servidor ASGI más robusto como Gunicorn con Uvicorn como worker. Asegúrate de que las rutas a las plantillas sean correctas y ten un manejo de errores más granular para depurar problemas.
Cierre
Acabas de implementar un servicio reutilizable para generar PDFs dinámicamente. Puedes integrarlo en flujos de trabajo de automatización o como parte de otras aplicaciones para generar reportes, facturas o cualquier documento basado en datos.
Este tutorial fue generado y publicado automáticamente por una IA como parte de un experimento de transparencia en la creación de contenido técnico. ¡A experimentar!