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

JSONPath

An RFC 9535 JSONPath expression and predicate language over jsonpath-rust. It evaluates $. queries against an Exchange JSON body.

    ctx.register_language("jsonpath", Box::new(JsonPathLanguage::new()))
        .expect("jsonpath not yet registered"); // allow-unwrap

    let lang = JsonPathLanguage::new();

    let customer_expr = lang
        .create_expression("$.customer")
        .expect("valid expression"); // allow-unwrap

    let active_pred = lang.create_predicate("$.active").expect("valid predicate"); // allow-unwrap

    let customer_expr = Arc::new(customer_expr);
    let active_pred = Arc::new(active_pred);
    let route = RouteBuilder::from("timer:tick?period=800&repeatCount=6")
        .route_id("language-jsonpath-demo")
        .process(move |mut exchange: camel_api::Exchange| {
            let c = Arc::clone(&counter_clone);
            Box::pin(async move {
                let n = c.fetch_add(1, Ordering::SeqCst) as usize;
                let active = (n as u64).is_multiple_of(2);
                let customer = customers[n % customers.len()];
                let body = json!({
                    "active": active,
                    "customer": customer,
                    "order": { "id": n + 1 }
                });
                exchange.input.body = Body::Json(body);
                Ok(exchange)
            })
        })
        .process({
            let expr = Arc::clone(&customer_expr);
            move |mut exchange: camel_api::Exchange| {
                let expr = Arc::clone(&expr);
                Box::pin(async move {
                    if let Ok(value) = expr.evaluate(&exchange).await
                        && let Some(name) = value.as_str()
                    {
                        exchange
                            .input
                            .set_header("customer", camel_api::Value::String(name.to_string()));
                    }
                    Ok(exchange)
                })
            }
        })
        .to("log:all-orders?showBody=true&showHeaders=true")
        .filter({
            let pred = Arc::clone(&active_pred);
            let handle = tokio::runtime::Handle::current();
            move |ex: &camel_api::Exchange| handle.block_on(pred.matches(ex)).unwrap_or(false)
        })
        .to("log:active-orders?showBody=true&showHeaders=true")
        .end_filter()
        .build()?;
YAML equivalent
- id: language-jsonpath-demo
  from: timer:tick?period=800&repeatCount=6
  steps:
    - set_body:
        value: '{"customer": "Alice", "active": true}'
    - set_header:
        key: customer
        jsonpath: "$.customer"
    - to: log:all-orders?showBody=true&showHeaders=true
    - filter:
        jsonpath: "$.active"
        steps:
          - to: log:active-orders?showBody=true&showHeaders=true

JsonPathLanguage validates the query prefix and syntax when it creates an Expression or Predicate. You register the language into CamelContext by name, then build expressions and predicates up front. The included example registers jsonpath and constructs one expression ($.customer) and one predicate ($.active) before the route. Expressions extract values from the JSON body. Predicates gate filter steps.

The query is trusted operator configuration. The JSON body is untrusted, adversary-controlled data under ADR-0032. Exchange data never enters the query string. The implementation stores the operator query and passes body content separately to jsonpath-rust. Resource bounds protect against large or deeply nested input. max_input_bytes bounds a text body before JSON parsing. The default is 16 MiB. max_depth bounds JSON nesting. The default is 64 levels.

Use JSONPath when the body contains structured JSON and you need to extract nested fields or test conditions. For flat header and body access, Simple is lighter and needs no JSON parsing.

Reference: Language SPI · JSONPath crate