Rules are easier to test than code: every rule is a pure function of its input. The Rule Engine ships three layers of test tooling — syntactic validation, single-rule dry runs, and full rule-set executions with monitoring.
Validate syntax
Run validation before saving any rule set. Three flavors:
/rules/validateJWT/rules/validate-yamlJWT/rules/validate-jsonJWTcurl -X POST https://appengine.appmint.io/rules/validate-yaml \
-H "x-org-id: $ORG" -H "x-customer: $USER" \
-H "Content-Type: application/json" \
-d '{"yamlContent": "version: 2.0\nrules:\n - id: TEST\n when: order.total > 100\n then:\n add_message: hi"}'
The response lists structural errors (missing id, malformed condition, unknown operator), unknown helper references, and warnings (e.g. a rule with no then block).
Dry-run a single rule
/rules/test-ruleJWTPass the rule and a testData payload. The engine evaluates it and returns the resolved branches:
curl -X POST https://appengine.appmint.io/rules/test-rule \
-H "x-org-id: $ORG" -H "x-customer: $USER" \
-H "Content-Type: application/json" \
-d '{
"rule": {
"id": "BULK",
"when": { ">=": ["order.lineCount", 5] },
"then": { "apply_discount": { "type": "percent", "value": 10 } },
"else": { "apply_discount": { "type": "percent", "value": 0 } }
},
"testData": { "order": { "lineCount": 7 } }
}'
Response:
{
"passed": true,
"branchTaken": "then",
"actions": { "apply_discount": { "type": "percent", "value": 10 } },
"evaluationTimeMs": 1.4,
"vars": {}
}
Run a full rule set with monitoring
/rule-engine/executeJWTPass options.logExecution: true and options.trackPerformance: true to capture per-rule timings and write the run to execution history.
curl -X POST https://appengine.appmint.io/rule-engine/execute \
-H "x-org-id: $ORG" -H "x-customer: $USER" \
-d '{
"rules": [ /* array of rules */ ],
"data": { /* input */ },
"options": { "logExecution": true, "trackPerformance": true, "enableDebug": true, "timeout": 5000 }
}'
enableDebug: true returns intermediate variable bindings and which branch each rule took.
Sample data fixtures
The repo ships canonical examples to copy from. Validate your data against the shape these expect:
| Example | Path |
|---|---|
| Bulk discount | src/rule-engine/examples/bulk-discount.yaml |
| Fraud gate | src/rule-engine/examples/fraud-gate.yaml |
| Order pipeline | src/rule-engine/examples/order-pipeline.yaml |
| Shipping path | src/rule-engine/examples/shipping-path.yaml |
| Order all-fields fixture | src/rule-engine/examples/order-all-fields.json |
| Invalid order fixture | src/rule-engine/examples/invalid-order.json |
Read execution history
/rules/execution-historyJWT| Query | Description |
|---|---|
executionId | One specific run |
ruleSetId | Filter by rule set |
dateFrom, dateTo | Time window |
success | Only failures (false) or successes (true) |
event | Trigger event filter |
limit, page | Paging |
Each record carries the rule set, input data hash, the resolved actions, and per-rule timings.
/rules/execution-statsJWT/rules/performance-metricsJWTThe x-customer header carries the user principal. The rule engine controllers are unusual in that they read this rather than relying on the global JWT guard alone — pass both the JWT and the customer record when integrating from a backend.