PDF Generation Guide
A comprehensive guide to PDF generation using the Report Flow API.
Overview
There are two modes for PDF generation:
| Mode | Endpoint | Response | Use Case |
|---|---|---|---|
| Sync Generation | /file/sync/single | PDF File | When immediate results are needed |
| Async Generation | /file/async/single | File URL | For batch processing or background tasks |
Sync Generation
Basic Usage
curl -X POST https://{workspaceId}.re-port-flow.com/v1/file/sync/single \
-H "AppKey: your-app-key" \
-H "SecretKey: your-secret-key" \
-H "Content-Type: application/json" \
-d '{
"designId": "550e8400-e29b-41d4-a716-446655440000",
"version": 1,
"content": {
"fileName": "invoice.pdf",
"params": {
"customerName": "John Doe",
"invoiceNumber": "INV-2024-001",
"items": [
{
"name": "Product A",
"price": 1000,
"quantity": 2
}
]
}
}
}' \
--output invoice.pdf
Response Headers
Content-Type: application/pdf
Content-Disposition: attachment; filename="invoice.pdf"
Content-Length: 123456
File-URL: https://re-port-flow.com/workspace-id/design/design-id/files/file-uuid
File-ID: file_abc123
JavaScript Implementation Example
const axios = require('axios');
const fs = require('fs');
async function generatePDF(params) {
try {
const response = await axios.post(
`https://${process.env.WORKSPACE_ID}.re-port-flow.com/v1/file/sync/single`,
{
designId: params.designId,
version: params.version,
content: {
fileName: params.fileName,
params: params.data
}
},
{
headers: {
'AppKey': process.env.APP_KEY,
'SecretKey': process.env.SECRET_KEY,
'Content-Type': 'application/json'
},
responseType: 'arraybuffer'
}
);
// Save to file
fs.writeFileSync(params.fileName, response.data);
// Get file URL
const fileUrl = response.headers['file-url'];
const fileId = response.headers['file-id'];
return { fileUrl, fileId };
} catch (error) {
console.error('PDF generation error:', error.response?.data || error.message);
throw error;
}
}
// Usage example
generatePDF({
designId: '550e8400-e29b-41d4-a716-446655440000',
version: 1,
fileName: 'invoice.pdf',
data: {
customerName: 'John Doe',
invoiceNumber: 'INV-2024-001',
items: [
{ name: 'Product A', price: 1000, quantity: 2 }
]
}
});
Async Generation
Use async generation for large PDF batches or to avoid timeouts.
Basic Usage
# 1. Generation request
curl -X POST https://{workspaceId}.re-port-flow.com/v1/file/async/single \
-H "AppKey: your-app-key" \
-H "SecretKey: your-secret-key" \
-H "Content-Type: application/json" \
-d '{
"designId": "550e8400-e29b-41d4-a716-446655440000",
"version": 1,
"content": {
"fileName": "invoice.pdf",
"params": {...}
}
}'
# Response example
{
"url": "https://re-port-flow.com/workspace-id/design/design-id/files/file-uuid",
"fileId": "file_abc123"
}
JavaScript Implementation Example (Polling)
async function generatePDFAsync(params) {
// 1. Async generation request
const response = await axios.post(
`https://${process.env.WORKSPACE_ID}.re-port-flow.com/v1/file/async/single`,
{
designId: params.designId,
version: params.version,
content: {
fileName: params.fileName,
params: params.data
}
},
{
headers: {
'AppKey': process.env.APP_KEY,
'SecretKey': process.env.SECRET_KEY,
'Content-Type': 'application/json'
}
}
);
const { url, fileId } = response.data;
// 2. Download file from URL
const pdfResponse = await axios.get(url, {
responseType: 'arraybuffer'
});
return {
data: pdfResponse.data,
url,
fileId
};
}
Multiple PDF Generation (ZIP)
Generate multiple PDFs at once and receive them as a ZIP file.
Sync Generation
async function generateMultiplePDFs(designId, contents) {
const response = await axios.post(
`https://${process.env.WORKSPACE_ID}.re-port-flow.com/v1/file/sync/multiple`,
{
designId,
version: 1,
contents // Array of ContentDto
},
{
headers: {
'AppKey': process.env.APP_KEY,
'SecretKey': process.env.SECRET_KEY
},
responseType: 'arraybuffer'
}
);
// Get file mapping from X-File-Mapping header
const fileMapping = JSON.parse(response.headers['x-file-mapping']);
console.log('Generated files:', fileMapping);
return response.data; // ZIP binary
}
// Usage example
const contents = [
{
fileName: 'invoice_001.pdf',
params: { customerName: 'John Doe', invoiceNumber: 'INV-001' }
},
{
fileName: 'invoice_002.pdf',
params: { customerName: 'Jane Smith', invoiceNumber: 'INV-002' }
}
];
const zipData = await generateMultiplePDFs('550e8400-...', contents);
fs.writeFileSync('invoices.zip', zipData);
Parameter Structure
Retrieving Design Parameters
Before generation, you can check the available parameter structure for a design:
curl -X GET https://{workspaceId}.re-port-flow.com/v1/file/design/parameter/{designId}?version=1 \
-H "AppKey: your-app-key" \
-H "SecretKey: your-secret-key"
Response Example:
{
"customerName": "string",
"invoiceNumber": "string",
"amount": "number",
"items": [
{
"name": "string",
"price": "number",
"quantity": "number"
}
],
"issueDate": "date"
}
Parameter Type Mapping
| Type | Description | Example |
|---|---|---|
string | Text string | "John Doe" |
number | Numeric value | 1000 |
date | Date (ISO 8601) | "2024-02-12" |
object | Nested object | { "name": "value" } |
array | Array | [{ "item": 1 }] |
Error Handling
Common Errors
400 Bad Request - Validation Error
{
"statusCode": 400,
"message": [
"designId must be a UUID",
"fileName can only contain alphanumeric characters, Japanese characters, hyphens, underscores, and dots"
],
"error": "Bad Request"
}
Solution:
- Check request body
- Verify file name format (regex:
^[a-zA-Z0-9\u3000-\uFFEF_.\-]+$)
500 Internal Server Error
{
"statusCode": 500,
"message": "Internal server error",
"error": "Internal Server Error"
}
Solution:
- Possible temporary server error
- Implement retry logic
- Contact support if it persists
Retry Strategy
async function generatePDFWithRetry(params, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await generatePDF(params);
} catch (error) {
if (error.response?.status === 500 && i < maxRetries - 1) {
// Retry with exponential backoff
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, i)));
continue;
}
throw error;
}
}
}
Best Practices
1. Timeout Settings
Sync generation times out after 30 seconds. Use async generation for large PDFs.
// Set timeout with axios
const response = await axios.post(url, data, {
timeout: 30000 // 30 seconds
});
2. File Name Sanitization
function sanitizeFileName(fileName) {
return fileName.replace(/[^a-zA-Z0-9\u3000-\uFFEF_.\-]/g, '_');
}
3. Parameter Validation
function validateParams(params, schema) {
// Validate against design parameter schema
for (const [key, type] of Object.entries(schema)) {
if (!(key in params)) {
throw new Error(`Required parameter ${key} is missing`);
}
// Type checking, etc.
}
}