Airpdf — Template schema
Un template Airpdf è un documento JSON strutturato che descrive la gerarchia
di nodi che i nodi render Node.js (react-pdf) convertono in PDF.
Gerarchia
Document
└── Page (una per pagina del PDF)
└── View (contenitore con style, simile a un <div>)
├── Text (testo + variabili {{var}})
├── Image (src: statico oppure variabile)
├── List (ripetizione da array di `data`)
└── Link (testo+href, href può essere variabile)
Ogni nodo ha:
-
type: uno didocument | page | view | text | image | list | link -
style: object con attributi CSS-like (vedi sotto) -
children: array di nodi figli - campi specifici del tipo
Variable syntax
I campi testuali supportano il placeholder Mustache-like {{path.to.value}}:
{ "type": "text", "children": ["Ciao {{customer.name}}!"] }
Path annidati, array indexing (items.0.sku) e helpers basilari
({{#if}}, {{#each}}) sono supportati dal render.
Supported style attrs
Subset di react-pdf (flexbox):
| Categoria | Attributi |
|---|---|
| Layout |
display, flexDirection, justifyContent, alignItems, gap |
| Box |
width, height, padding(Top/Right/Bottom/Left), margin... |
| Border |
borderWidth, borderColor, borderRadius |
| Background |
backgroundColor |
| Text |
fontSize, fontFamily, fontWeight, color, textAlign, lineHeight |
| Page only |
size (A4/Letter/...), orientation, margin |
Valori supportati: px (default numerico), %, percentuali per width/height.
Esempio minimo
template.json:
{
"type": "document",
"children": [
{
"type": "page",
"style": { "size": "A4", "padding": 40, "fontFamily": "Helvetica" },
"children": [
{
"type": "view",
"style": { "flexDirection": "row", "justifyContent": "space-between" },
"children": [
{ "type": "text", "style": { "fontSize": 18, "fontWeight": "bold" },
"children": ["Fattura {{invoice.number}}"] },
{ "type": "image",
"src": "{{brand.logo_url}}",
"style": { "width": 80, "height": 80 } }
]
},
{
"type": "list",
"from": "items",
"style": { "marginTop": 20 },
"item": {
"type": "view",
"style": { "flexDirection": "row", "justifyContent": "space-between" },
"children": [
{ "type": "text", "children": ["{{this.sku}} × {{this.qty}}"] },
{ "type": "text", "children": ["€ {{this.price}}"] }
]
}
}
]
}
]
}
data:
{
"invoice": { "number": "2026-001" },
"brand": { "logo_url": "https://acme.com/logo.png" },
"items": [
{ "sku": "SKU-1", "qty": 2, "price": "19.90" },
{ "sku": "SKU-2", "qty": 1, "price": "49.00" }
]
}
variables_schema
Ogni Template salva un variables_schema JSON Schema Draft 2020-12 che
documenta e valida il payload data in ingresso. L'editor integrato genera
lo schema automaticamente; il render lo usa per errori chiari prima del
rendering:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["invoice", "items"],
"properties": {
"invoice": {
"type": "object",
"required": ["number"],
"properties": { "number": { "type": "string" } }
},
"items": {
"type": "array",
"items": {
"type": "object",
"required": ["sku", "qty", "price"],
"properties": {
"sku": { "type": "string" },
"qty": { "type": "integer", "minimum": 1 },
"price": { "type": "string", "pattern": "^\\d+(\\.\\d{1,2})?$" }
}
}
}
}
}
Violazioni producono un 422 VALIDATION_FAILED con path + messaggio per
ciascun campo non conforme.