Minimales Beispiel
Ein Minimales setup besteht aus 2 Kernbestandteilen
- Ein Script im Frontend.
- Ein Flow im Node Red.
Folgende flyze.services müssen für ein Reporting laufen

| Service | Beschreibung |
|---|---|
| ConnectorApi | Wird als Gateway genutzt, um die Reporting Api zu erreichen. |
| NodeRed | NodeRed ist kein muss, aber hilfreich um die Reporting Api zu erreichen. |
| ReportingApi | Generiert den PDF Report. |
1. Scripting im Frontend
Folgend ein Action Script welches auf ein Button gelegt wurde um ein Report zu generieren. In diesem Script können
reportName, reportRoute, reportData angepasst werden um mit dem nachfolgend aufgeführten NodeRed Flow zu interagieren.
| Parameter | Beschreibung |
|---|---|
| reportName | Kann frei gewählt werden. |
| reportRoute | Muss mit dem NodeRed Enpoint übereinstimmen |
| reportData | Stelle die Daten bereit, die beim generieren des Reports verwendet werden |
const CONNECTOR_API_URL = fyzPlatform.env.get().config.connectorApiUrl;
// Set The NodeRed Endpoint you have chosen
const reportRoute = 'generateReport';
// Set the file name you want the user to have when downloading
const reportDate = "2025-09-01"
const reportName = `${reportDate}_report`;
// Set the date you want to use inside the endpoint
const reportData = {
test: "1234",
testArray: [
{ id: `1`, name: "content1" },
{ id: `2`, name: "content2" }
]
}
// execute the report
generateReport(reportRoute, reportName, reportData);
// helper function - call the node red endpoint
function generateReport(route, name, data) {
fyzUtils.httpApi
.executeRequestsAsync([{
action: 'POST',
url: CONNECTOR_API_URL + '/api/data/connect',
body: {
Configuration: {
Endpoint: 'FLYZE_NODE_RED',
Route: `${route}`,
Authentication: false
},
ApiConfig: data
},
responseType: "arraybuffer"
}], (res) => {
if (res && res[0]) {
makeBrowserDownload(res[0], name);
}
})
}
// helper function - download the file to browser
function makeBrowserDownload(fileData, fileName) {
// Create a blob from the response
const blob = new Blob([fileData], { type: "application/pdf" });
// Create a temporary download link
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `${fileName}.pdf`; // filename
document.body.appendChild(a);
a.click();
// Clean up
setTimeout(() => {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 0);
}
1. Flow im NodeRed
Damit das obige Script funktioniert, kann folgender NodeRed Flow verwendet werden:
Der Flow kann an den passenden stellen so angepasst werden, das ein Bericht so generiert wird, wie gewünscht. Dazu können in den Funktionen
Logo, Report Data, Page Header, PDF Body, und Page Footer die Werte angepasst werden.
| Funktion | Beschreibung |
|---|---|
| Logo | Hier kann das Logo in .svg angegeben werden. |
| Report Data | Hier können die Daten die im Report verwendet werden, deklariert werden. |
| Page Header | Hier kann das Aussehen der Seitenkopfzeile definiert werden. |
| PDF BODY | Hier kann das Aussehen des PDFs definiert werden. |
| Page Footer | Hier kann das Aussehen der Seitenfußzeile definiert werden. |
[
{
"id": "30185f1ee6edfa2a",
"type": "http in",
"z": "26ecfdaf11c9fd26",
"name": "[/generateReport] Endpoint",
"url": "/generateReport",
"method": "post",
"upload": false,
"skipBodyParsing": false,
"swaggerDoc": "",
"x": 310,
"y": 540,
"wires": [
[
"9eaf35c32f79644b"
]
]
},
{
"id": "dc1d843cef0e8697",
"type": "http request",
"z": "26ecfdaf11c9fd26",
"name": "Send Request to Reporting Api",
"method": "POST",
"ret": "bin",
"paytoqs": "ignore",
"url": "http://reporting-api:8080/export",
"tls": "",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [],
"x": 1690,
"y": 540,
"wires": [
[
"5cad433444728aa4"
]
]
},
{
"id": "5cad433444728aa4",
"type": "http response",
"z": "26ecfdaf11c9fd26",
"name": "",
"statusCode": "",
"headers": {},
"x": 1910,
"y": 540,
"wires": []
},
{
"id": "e2667eff7ac96456",
"type": "function",
"z": "26ecfdaf11c9fd26",
"name": "Generate Report Configuration",
"func": "const reportData = msg.payload.reportData;\nconst reportTempate = msg.payload.reportTemplate;\n\nmsg.payload = {\n template: reportTempate.body,\n data: JSON.stringify(reportData),\n marginOptions: {\n top: \"22mm\",\n bottom: \"22mm\",\n left: \"10mm\",\n right: \"10mm\"\n },\n headerFooterOptions: {\n \"setHeaderFooter\": true,\n \"headerTemplate\": reportTempate.header,\n \"footerTemplate\": reportTempate.footer\n },\n Landscape: false,\n config: {\n dynamic: true,\n type: `PDF`,\n typeConfig: {\n filename: \"Check Car Report.pdf\"\n }\n }\n}\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1390,
"y": 540,
"wires": [
[
"dc1d843cef0e8697"
]
]
},
{
"id": "9eaf35c32f79644b",
"type": "function",
"z": "26ecfdaf11c9fd26",
"name": "Logo",
"func": "const myLogo = `<svg viewBox=\"0 0 121 117\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M38.1709 10.1491C16.7402 17.5182 17.9957 39.5376 17.9957 39.5376H8V56.5897H17.9077V108.309H35.652V56.5897H45.4757V39.5376H35.652V39.174C35.692 37.3197 36.3237 29.2512 44.2363 26.3859C47.079 25.3549 50.8534 24.9872 55.8792 25.8184V108.309H73.5715V12.9984C73.5515 12.9984 73.5915 12.9984 73.5715 12.9984V10.0652C57.6824 7.01202 46.3074 7.60347 38.1709 10.1491Z\" fill=\"black\"/>\n<path d=\"M112.743 84.6641H89.0973V108.294H112.743V84.6641Z\" fill=\"#0F6FFF\"/>\n</svg>\n`;\n\nmsg.payload = {\n ...msg.payload,\n logo: myLogo\n}\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 850,
"y": 540,
"wires": [
[
"fc909feaa1445631"
]
]
},
{
"id": "7101b4b5b9b53c8d",
"type": "comment",
"z": "26ecfdaf11c9fd26",
"name": "Endpoint Of Your Report",
"info": "# Test With:\n\nSyntax: `nodered-domain`/`endpointName`\nExample: `nodered.sub1.flyze.io/generateReport`",
"x": 310,
"y": 500,
"wires": []
},
{
"id": "b6dd5751c0789aef",
"type": "function",
"z": "26ecfdaf11c9fd26",
"name": "Page Footer",
"func": "const footerTemplate = `\n<style>\n .page-header {\n display: flex;\n flex-direction: row;\n width: 100%;\n gap: 16px;\n margin: 0px 16px;\n }\n\n .page-header-start {\n display: flex;\n }\n\n .page-header-start-logo {\n display: flex;\n\n flex-direction: column;\n justify-content: center;\n width: 48px;\n height: 48px;\n overflow: hidden;\n }\n\n #info {\n display: flex;\n justify-content: center;\n align-items: center;\n font-size: 12px;\n }\n\n .page-header-center {\n display: flex;\n flex-direction: column;\n width: 100%;\n justify-content: center;\n align-items: center;\n }\n\n .page-header-end {\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: flex-end;\n }\n\n .page-header-end-date {\n display: flex;\n width: 100%;\n height: 100%;\n justify-content: end;\n align-items: center;\n font-size: 12px;\n }\n .page-header-end-pages {\n display: flex;\n width: 100%;\n height: 100%;\n justify-content: end;\n align-items: center;\n font-size: 12px;\n }\n</style>\n<div class=\"page-header\">\n <div class=\"page-header-start\">\n <div class=\"page-header-start-logo\">${msg.payload.reportData.logo}</div>\n </div>\n <div class=\"page-header-center\">\n <div id=\"info\">flyze.solutions GmbH - Example Report</div>\n </div>\n <div class=\"page-header-end\">\n <div class=\"page-header-end-date\">${new Date().toLocaleDateString()}</div>\n <div class=\"page-header-end-pages\">\n Seite <span class=\"pageNumber\"></span> von<span class=\"totalPages\"></span>\n </div>\n </div>\n</div>\n`\n\nmsg.payload = {\n ...msg.payload,\n reportTemplate: {\n ...msg.payload.reportTemplate,\n footer: footerTemplate\n }\n}\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 870,
"y": 780,
"wires": [
[
"e2667eff7ac96456",
"f5285380de5542c3"
]
]
},
{
"id": "e8364391bb625c9e",
"type": "function",
"z": "26ecfdaf11c9fd26",
"name": "Page Header",
"func": "const headerTemplate = `\n<style>\n .page-header {\n display: flex;\n flex-direction: row;\n width: 100%;\n gap: 16px;\n margin: 0px 16px;\n }\n\n .page-header-start {\n display: flex;\n }\n\n .page-header-start-logo {\n display: flex;\n\n flex-direction: column;\n justify-content: center;\n width: 48px;\n height: 48px;\n overflow: hidden;\n }\n\n #info {\n display: flex;\n justify-content: center;\n align-items: center;\n font-size: 12px;\n }\n\n .page-header-center {\n display: flex;\n flex-direction: column;\n width: 100%;\n justify-content: center;\n align-items: center;\n }\n\n .page-header-end {\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: flex-end;\n }\n\n .page-header-end-date {\n display: flex;\n width: 100%;\n height: 100%;\n justify-content: end;\n align-items: center;\n font-size: 12px;\n }\n .page-header-end-pages {\n display: flex;\n width: 100%;\n height: 100%;\n justify-content: end;\n align-items: center;\n font-size: 12px;\n }\n</style>\n<div class=\"page-header\">\n <div class=\"page-header-start\">\n <div class=\"page-header-start-logo\">${msg.payload.reportData.logo}</div>\n </div>\n <div class=\"page-header-center\">\n <div id=\"info\">flyze.solutions GmbH - Example Report</div>\n </div>\n <div class=\"page-header-end\">\n <div class=\"page-header-end-pages\">\n Seite <span class=\"pageNumber\"></span> von<span class=\"totalPages\"></span>\n </div>\n <div class=\"page-header-end-date\">${new Date().toLocaleDateString()}</div>\n </div>\n</div>\n`;\n\nmsg.payload = {\n ...msg.payload,\n reportTemplate: {\n ...msg.payload.reportTemplate,\n header: headerTemplate\n }\n}\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 870,
"y": 660,
"wires": [
[
"b4421ea9f1efe6b1"
]
]
},
{
"id": "b4421ea9f1efe6b1",
"type": "function",
"z": "26ecfdaf11c9fd26",
"name": "PDF BODY",
"func": "const data = msg.payload.reportData;\n\nconst styles = `\n html {\n -webkit-print-color-adjust: exact;\n font-family: \"Calibri\", sans-serif;\n }\n .logo {\n margin: 16px;\n padding: 16px;\n width: 48px;\n }\n\n body { \n }\n\n .margin {\n margin-bottom: 16px;\n }\n`;\n\nconst content = `\n<div class=\"margin\">\n <div style=\"color: red\">Show If value of test equals 123, else show [No Content]</div>\n <div>${data.test === \"123\" ? data.test : \"No Content\"}</div>\n</div>\n\n<div>Content No Page Break</div>\n\n<div ngFor=\"let test of testArray\">\n <div>Id: {{test.id}}</div>\n <div>Name: {{test.name}}</div>\n</div>\n\n<div style=\"page-break-after: always;\"></div>\n\n<div>Content With Page Break</div>\n<div ngFor=\"let test of testArray\" style=\"page-break-after: always;\">\n <div>Id: {{test.id}}</div>\n <div>Name: {{test.name}}</div>\n</div>\n\n<div>Logo Example, string replacement</div>\n<div class=\"logo margin\">\n ${data.logo}\n</div>\n<div>Logo Example, data rendering</div>\n<div class=\"logo margin\">\n {{logo}}\n</div>\n`;\n\nconst htmlTemplate = `\n<html>\n <title>Test</title>\n <style>\n ${styles}\n </style>\n\n <body>\n ${content}\n </body>\n</html>`\n\nmsg.payload = {\n ...msg.payload,\n reportTemplate: {\n ...msg.payload.reportTemplate,\n body: htmlTemplate\n }\n}\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 870,
"y": 720,
"wires": [
[
"b6dd5751c0789aef"
]
]
},
{
"id": "037ad02b188af2e4",
"type": "comment",
"z": "26ecfdaf11c9fd26",
"name": "Change Functions to Design PDF",
"info": "",
"x": 930,
"y": 500,
"wires": []
},
{
"id": "93960a29cd64e284",
"type": "comment",
"z": "26ecfdaf11c9fd26",
"name": "Scripting Example",
"info": "# Call from Scripting\n\n``` javascript\nconst CONNECTOR_API_URL = fyzPlatform.env.get().config.connectorApiUrl;\n\n// Set The NodeRed Endpoint you have chosen \nconst reportRoute = 'generateReport';\n\n// Set the file name you want the user to have when downloading\nconst reportDate = \"2025-09-01\"\nconst reportName = `${reportDate}_report`;\n\n// Set the date you want to use inside the endpoint\nconst reportData = {\n test: \"1234\",\n testArray: [\n { id: `1`, name: \"content1\" },\n { id: `2`, name: \"content2\" }\n ]\n}\n\n// execute the report\ngenerateReport(reportRoute, reportName, reportData);\n\n\n// helper function - call the node red endpoint\nfunction generateReport(route, name, data) {\n fyzUtils.httpApi\n .executeRequestsAsync([{\n action: 'POST',\n url: CONNECTOR_API_URL + '/api/data/connect',\n body: {\n Configuration: {\n Endpoint: 'FLYZE_NODE_RED',\n Route: `${route}`,\n Authentication: false\n },\n ApiConfig: data\n },\n responseType: \"arraybuffer\"\n }], (res) => {\n if (res && res[0]) {\n makeBrowserDownload(res[0], name);\n }\n })\n}\n\n// helper function - download the file to browser\nfunction makeBrowserDownload(fileData, fileName) {\n // Create a blob from the response\n const blob = new Blob([fileData], { type: \"application/pdf\" });\n\n // Create a temporary download link\n const url = window.URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = `${fileName}.pdf`; // filename\n document.body.appendChild(a);\n a.click();\n\n // Clean up\n setTimeout(() => {\n document.body.removeChild(a);\n window.URL.revokeObjectURL(url);\n }, 0);\n}\n```",
"x": 290,
"y": 440,
"wires": []
},
{
"id": "fc909feaa1445631",
"type": "function",
"z": "26ecfdaf11c9fd26",
"name": "Report Data",
"func": "\nmsg.payload = {\n reportData: {\n ...msg.payload\n }\n}\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 870,
"y": 600,
"wires": [
[
"e8364391bb625c9e"
]
]
},
{
"id": "b1119e7cbcccb861",
"type": "comment",
"z": "26ecfdaf11c9fd26",
"name": "Report Configuration",
"info": "",
"x": 1350,
"y": 500,
"wires": []
},
{
"id": "95a29bd092ef79ae",
"type": "comment",
"z": "26ecfdaf11c9fd26",
"name": "Add a logo",
"info": "",
"x": 720,
"y": 540,
"wires": []
},
{
"id": "89c1f931f118ec0b",
"type": "comment",
"z": "26ecfdaf11c9fd26",
"name": "Pass Data",
"info": "",
"x": 720,
"y": 600,
"wires": []
},
{
"id": "23765e2d90ba3882",
"type": "comment",
"z": "26ecfdaf11c9fd26",
"name": "Define Header Design",
"info": "",
"x": 680,
"y": 660,
"wires": []
},
{
"id": "67a0070037431d40",
"type": "comment",
"z": "26ecfdaf11c9fd26",
"name": "Define Footer Design",
"info": "",
"x": 680,
"y": 780,
"wires": []
},
{
"id": "4356b43a505d4ba7",
"type": "comment",
"z": "26ecfdaf11c9fd26",
"name": "Define PDF Design",
"info": "",
"x": 690,
"y": 720,
"wires": []
},
{
"id": "f5285380de5542c3",
"type": "debug",
"z": "26ecfdaf11c9fd26",
"name": "debug 4",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 1320,
"y": 600,
"wires": []
}
]
