node-red-contrib-data-validation-engine
Version:
A simple rule-based data validation node for Node-RED (sheetsExist, sheetHasColumns) with UI builder and JSON config file support.
200 lines (144 loc) • 4.8 kB
Markdown
# node-red-contrib-data-validation-engine
A lightweight rule-based validator for structured sheet-like data in Node-RED.
This build focuses on two common checks:
* **`sheetsExist`** — ensure specific sheets exist and are non-empty.
* **`sheetHasColumns`** — ensure a sheet exposes required columns/paths.
It supports:
* UI rule builder with an **Add/Edit** dialog
* Optional **JSON config file** (load/save/lock/watch)
* Simple **rule-level condition** (attr/op/rhs)
* Typed RHS (string/number/bool/msg/flow/global/env/jsonata)
* Status badge and a structured result on `msg.validation`
## Install
```bash
npm i node-red-contrib-data-validation-engine
# or inside your Node-RED userDir (usually ~/.node-red)
cd ~/.node-red
npm i node-red-contrib-data-validation-engine
```
Restart Node-RED. You’ll find the node under **function** as **data-validation**.
## Quick Start
1. Drop **data-validation** node in a flow.
2. Choose your **Input** source (`msg`, `flow`, or `global` + path).
* Example: `msg.data` where `data` is an object:
```json
{
"NAME":[{...}],
"PRICE":[{ "Project":"P1", "Layout":"L1" }]
}
```
3. Add rules (dialog) or **Load from file**.
4. Wire a **debug** node and send any message.
5. Read results on `msg.validation`.
## Node Properties
### Input
* **Source**: `msg` | `flow` | `global`
* **Path**: dot-path under the chosen scope (e.g. `data`).
The result must be an **object** keyed by sheet names (arrays or objects).
### Config file (optional)
* **Use config file**: toggle on to use a JSON file under your Node-RED `userDir`.
* **Path**: relative or absolute. Relative resolves under `userDir`.
* **Load from file**: reads JSON and populates the Rules table (and dialog).
* **Save to file**: writes the current UI rules to the JSON file.
* **Lock to file**: disables the rules UI and always uses the file on deploy/runtime.
* **Watch**: auto-reload rules when the file changes.
### Default level
* Fallback level for rules that do not specify one: `info` | `warning` | `error`.
## Rules
### 1) `sheetsExist`
Checks that each listed sheet exists and is non-empty.
```json
{
"type": "sheetsExist",
"id": "RULE_SHEETS",
"description": "Core sheets exist",
"requiredSheets": ["NAME","PRICE"],
"level": "error",
"conditions": {
"and": [
{ "attribute": "TM", "operator": "==", "rhsType": "str", "value": "RTC" }
]
}
}
```
### 2) `sheetHasColumns`
Checks headers/paths on the *shape* of the sheet (first object for arrays; object otherwise).
```json
{
"type": "sheetHasColumns",
"id": "RULE_LAYOUT_COLS",
"description": "NAME must have name, grade",
"sheet": "Layout",
"requiredColumns": ["name","grade"],
"level": "error",
"conditions": {
"and": [
{ "attribute": "SomeContext.Value", "operator": "regex", "rhsType": "str", "value": "^P" }
]
}
}
```
#### Operators
`==`, `!=`, `contains`, `!contains`, `regex`, `isEmpty`, `!isEmpty`
#### RHS types
`str`, `num`, `bool`, `msg`, `flow`, `global`, `env`, `jsonata`
> Example `jsonata`: `$.now()` or mapping something derived from `msg`.
## Output
On success the node sets:
```json
msg.validation = {
"logs": [
{
"id": "RULE_LAYOUT_COLS",
"type": "sheetHasColumns",
"level": "error|warning|info",
"message": "Missing column 'name' in 'NAME'.",
"description": "NAME must have name, grade"
}
],
"counts": { "info": 6, "warning": 1, "error": 2, "total": 9 }
}
```
The node status shows a compact summary: `E:x W:y I:z`.
## JSON Config File
If you prefer to keep rules in a file:
```json
[
{
"type": "sheetsExist",
"description": "Core sheets exist",
"requiredSheets": ["NAME","PRICE"],
"level": "error"
},
{
"type": "sheetHasColumns",
"description": "NAME must have name, grade",
"sheet": "NAME",
"requiredColumns": ["name","grade"],
"level": "error"
}
]
```
* **Load from file** fills the UI with these rules.
* **Save to file** writes current UI rules back to the file.
* **Lock to file** forces runtime to read from file, disabling the local editor.
## Best Practices
* Feed the node a clean, **object-of-sheets** structure.
* For column checks, ensure the first row is representative (object with keys).
* Use **conditions** sparingly to gate rule execution.
* Keep rule IDs stable if you post-process `msg.validation.logs`.
## Troubleshooting
* **“invalid input root” status**: the configured `msg/flow/global` path doesn’t resolve to an object.
* **Config file not found**: path must be under `userDir` if relative; file must be `.json`.
* **No changes after editing file**: enable **Watch**, or hit **Deploy** to reload.
## License
MIT @AIOUB SAI