Skip to content

EdvaldoLima/HTMLforPDF

Repository files navigation

HTMLforPDF

A service for generating PDFs from URLs using Playwright. Supports synchronous generation (direct response) and asynchronous generation via RabbitMQ queue with webhook delivery.

Prerequisites

  • Node.js >= 18
  • RabbitMQ (for asynchronous generation via queue)
  • Playwright browsers (installed automatically, or run npx playwright install chromium)

Installation

git clone <repo-url>
cd HTMLforPDF
npm install

Environment Variables

Create a .env file in the project root:

PORT=3000
RABBITMQ_URL=amqp://localhost
PDF_QUEUE_NAME=html_for_pdf_job
WORKER_CONCURRENCY=1
Variable Default Description
PORT 3000 HTTP server port
RABBITMQ_URL amqp://localhost RabbitMQ connection URL
PDF_QUEUE_NAME html_for_pdf_job RabbitMQ queue name
WORKER_CONCURRENCY 1 Number of jobs processed in parallel

Scripts

npm run dev          # Development server (with hot-reload)
npm run dev:worker   # Development worker (with hot-reload)
npm start            # Production server
npm run worker       # Production worker
npm run lint         # Lint
npm run lint:fix     # Lint with auto-fix
npm run format       # Format code with Prettier
npm test             # Tests

API Routes

Base path: /api/pdfs


POST /api/pdfs/

Generates a PDF synchronously and returns the file in the response.

Request Body

{
  "url": "https://example.com",
  "options": {
    "format": "A4",
    "landscape": true,
    "margin": { "top": "2cm", "bottom": "2cm" }
  }
}
Field Type Required Description
url string URL of the page to convert to PDF
options object PDF generation options (see table below)

Responses

Status Content-Type Description
200 application/pdf Generated PDF file
422 application/json Validation error (invalid fields)
500 application/json Internal error

422 error example:

{
  "errors": [
    { "field": "url", "message": "The url field must be a valid URL", "rule": "url" }
  ]
}

POST /api/pdfs/jobs

Queues PDF generation asynchronously. The PDF will be generated by the worker and sent to the provided webhook URL.

Request Body

{
  "url": "https://example.com",
  "webhookUrl": "https://my-server.com/webhook/pdf",
  "options": {
    "format": "A3",
    "printBackground": true
  }
}
Field Type Required Description
url string URL of the page to convert to PDF
webhookUrl string URL that will receive the generated PDF via POST
options object PDF generation options (see table below)

Responses

Status Description
202 { "status": "queued" } — Job queued successfully
422 Validation error
500 Internal error

PDF Generation Options (options)

All fields below are optional. Default values applied: format: "A4" and printBackground: true.

Field Type Description
scale number Rendering scale (between 0.1 and 2, default: 1)
displayHeaderFooter boolean Display header and footer in the PDF
headerTemplate string HTML template for the header
footerTemplate string HTML template for the footer
printBackground boolean Print background graphics (default: true)
landscape boolean Landscape orientation
pageRanges string Page ranges (e.g., "1-5, 8")
format string Paper format (default: "A4")
width string | number Custom width (e.g., "8.5in", 100)
height string | number Custom height (e.g., "11in", 200)
margin object Margins: { top, right, bottom, left } (e.g., "1cm", "10px")
preferCSSPageSize boolean Use page size defined via CSS @page
tagged boolean Generate PDF with accessibility tags
outline boolean Generate outline/bookmarks from headings

Accepted format values: Letter, Legal, Tabloid, Ledger, A0, A1, A2, A3, A4, A5, A6

Accepted units for width, height, and margin: px, in, cm, mm

Available classes for headerTemplate and footerTemplate:

Class Injected value
date Formatted date
title Document title
url Document URL
pageNumber Current page number
totalPages Total number of pages

Webhook

When a job is processed by the worker (via POST /api/pdfs/jobs), the generated PDF is sent via POST to the provided webhookUrl.

Request Format

  • Method: POST
  • Content-Type: multipart/form-data
  • File field: file
  • Filename: file.pdf
  • MIME type: application/pdf

Equivalent cURL Example

curl -X POST https://my-server.com/webhook/pdf \
  -F "file=@file.pdf;type=application/pdf"

What Your Webhook Endpoint Should Expect

Your server should accept a POST request with multipart/form-data containing a file field with the PDF binary. Example using Express:

import multer from 'multer';

const upload = multer({ dest: 'uploads/' });

app.post('/webhook/pdf', upload.single('file'), (req, res) => {
  console.log('PDF received:', req.file);
  res.sendStatus(200);
});

Note: The worker considers the delivery successful when the webhook returns an HTTP 2xx status. Any other status will be logged as an error.

License

ISC — Edvaldo Lima