Volver a las notas

Crea tu API generadora de PDFs con FastAPI y Plantillas HTML

18 de octubre de 2026·
fastapipdfhtmlmicroserviciospython

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!