API
Preview API
Generate lightweight HTML previews for the report designer with first-page-only rendering.
Endpoint
POST /api/preview
The preview endpoint renders only the first page of a report as HTML. It is optimized for speed and designed for use in live designer tools where fast feedback is essential.
When to use preview
Use the preview endpoint when:
- Building a live report designer that needs instant visual feedback
- Rendering thumbnails of report templates
- Validating layout before committing to a full render
For full multi-page rendering, use the Render API instead.
Request
The request format is the same as the render endpoint, but always returns HTML for the first page only:
{
"template": {
"version": "1.0",
"type": "report",
"page": { "size": "A4", "orientation": "portrait" },
"bands": [
{
"type": "header",
"height": 60,
"components": [
{
"type": "text",
"position": { "x": 0, "y": 20, "width": 300, "height": 30 },
"content": "{{title}}",
"fontSize": 20,
"fontWeight": "bold"
}
]
},
{
"type": "detail",
"height": 28,
"dataBinding": "items",
"components": [
{
"type": "text",
"position": { "x": 0, "y": 4, "width": 200, "height": 20 },
"content": "{{item.name}}",
"fontSize": 12
}
]
}
]
},
"data": {
"title": "Preview Report",
"items": [{ "name": "Item 1" }, { "name": "Item 2" }, { "name": "Item 3" }]
}
}
Response
The response is always JSON with the first page rendered as HTML:
{
"output": "<div class=\"report page-1\">...</div>",
"metadata": {
"pageCount": 1,
"totalPages": 3,
"renderTimeMs": 12,
"format": "html",
"preview": true
}
}
Note the metadata includes totalPages (how many pages the full report would have) and preview: true to distinguish from a full render.
Performance
The preview endpoint is typically 3-5x faster than a full render because it:
- Stops band expansion after the first page fills
- Skips PDF conversion entirely
- Returns minimal HTML without pagination markup
Typical response times:
| Report complexity | Preview | Full render |
|---|---|---|
| Simple (1 page) | ~5ms | ~15ms |
| Medium (5 pages) | ~8ms | ~40ms |
| Large (50 pages) | ~10ms | ~200ms |
Example with curl
curl -X POST http://localhost:3000/api/preview \
-H "Content-Type: application/json" \
-d '{
"template": {
"version": "1.0",
"type": "report",
"page": { "size": "A4", "orientation": "portrait" },
"bands": [
{
"type": "header",
"height": 40,
"components": [
{
"type": "text",
"position": { "x": 0, "y": 10, "width": 200, "height": 20 },
"content": "Preview Test",
"fontSize": 16
}
]
}
]
},
"data": {}
}'
Integration with the designer
The preview endpoint pairs naturally with the ReportViewer component. As users edit the schema in a designer UI, debounce changes and call the preview endpoint for real-time visual feedback:
// Debounce schema changes, then preview
const previewReport = debounce(async (schema, data) => {
const res = await fetch('/api/preview', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ template: schema, data }),
})
const { output } = await res.json()
setPreviewHtml(output)
}, 300)
Next steps
- Render API — full rendering for production output
- Validate API — validate schemas before preview
- React / Next.js Integration — embed previews in React apps