Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Quick Start

Build your first rule in minutes.

Prerequisite reading: rules and mappings are written in JSONLogic. If you’ve never used it, skim the Data Access, Comparison Operators, and Conditionals sections first — they cover everything in the examples below.

Create a Simple Rule

Rules are defined in JSON and consist of actions (tasks) that process data sequentially.

use dataflow_rs::prelude::*;
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Define a rule that loads the payload into `data.input` and then
    // transforms it. Letting `parse_json` seed `data` is the idiomatic
    // pattern — handlers don't have to reach into `message.context`.
    let rule_json = r#"{
        "id": "greeting_rule",
        "name": "Greeting Rule",
        "tasks": [
            {
                "id": "load",
                "name": "Load Payload",
                "function": {
                    "name": "parse_json",
                    "input": { "source": "payload", "target": "input" }
                }
            },
            {
                "id": "create_greeting",
                "name": "Create Greeting",
                "function": {
                    "name": "map",
                    "input": {
                        "mappings": [
                            {
                                "path": "data.greeting",
                                "logic": { "cat": ["Hello, ", {"var": "data.input.name"}, "!"] }
                            }
                        ]
                    }
                }
            }
        ]
    }"#;

    let rule = Workflow::from_json(rule_json)?;

    // Builder is the recommended construction path. Compiles all
    // JSONLogic up-front; fails loud on bad config.
    let engine = Engine::builder().with_workflow(rule).build()?;

    // Create a message from a serde_json payload. `parse_json` will copy
    // it into `data.input` at workflow start.
    let mut message = Message::from_value(&json!({"name": "World"}));

    // Process the message.
    engine.process_message(&mut message).await?;

    // Print the result.
    println!("Greeting: {:?}", message.data()["greeting"]);

    Ok(())
}

Try It Interactively

Want more features? Try the Full Debugger UI with step-by-step execution and rule visualization.

Understanding the Code

  1. Rule Definition - JSON structure defining actions (tasks) to execute
  2. Engine Creation - Compiles all JSONLogic expressions at startup
  3. Message Creation - Input data wrapped in a Message structure
  4. Processing - Engine evaluates each rule’s condition and executes matching actions
  5. Result - Modified message with transformed data and audit trail

Add Validation

Extend your rule with data validation:

{
    "id": "validated_rule",
    "name": "Validated Rule",
    "tasks": [
        {
            "id": "validate_input",
            "name": "Validate Input",
            "function": {
                "name": "validation",
                "input": {
                    "rules": [
                        {
                            "logic": { "!!": {"var": "data.name"} },
                            "message": "Name is required"
                        }
                    ]
                }
            }
        },
        {
            "id": "create_greeting",
            "name": "Create Greeting",
            "function": {
                "name": "map",
                "input": {
                    "mappings": [
                        {
                            "path": "data.greeting",
                            "logic": { "cat": ["Hello, ", {"var": "data.name"}, "!"] }
                        }
                    ]
                }
            }
        }
    ]
}

Next Steps