Cameleer

Bean component

The bean component calls your own Rust code, registered in the registry under a name, from a route.

Scheme: bean: · Also: class: (see class) · Crate: cameleer-core · Cargo feature: none, always included (build features) · Consumer: no · Producer: yes · Apache Camel: Bean

When to use it

  • Put business logic (pricing, scoring, validation) in plain Rust functions and call them from YAML or Rust routes.
  • Give an AI agent route a deterministic tool, such as a fraud score, that runs in-process.
  • Reuse one service object with several named methods (?method=score, ?method=explain).

URI format

text
bean:beanName[?method=name]

Example

yaml example: bean-fraud-score
- route:
    id: score-payment
    from:
      uri: direct:score
      steps:
        - to: bean:fraudScorer?method=score
        - setBody:
            simple: "risk=${body}"

The bean is registered from Rust before the routes start. Methods added with method_value return the new body:

rust
use cameleer_core::component::bean::{bind_bean, BeanMethods};
use cameleer_core::prelude::*;

pub fn register(ctx: &CamelContext) {
    let scorer = BeanMethods::new()
        .method_value("score", |ex: &Exchange| {
            let amount: f64 = ex.body().to_string().parse().unwrap_or(0.0);
            Ok(Value::from(if amount > 1000.0 { "high" } else { "low" }))
        })
        .method("tag", |ex: &mut Exchange| {
            ex.set_header("scored", true);
            Ok(())
        });
    bind_bean(ctx.registry(), "fraudScorer", scorer);
}

Sending 2500 to direct:score returns risk=high.

Rust DSL

rust
use cameleer_core::prelude::*;

pub fn routes(ctx: &CamelContext) -> Result<()> {
    ctx.add_routes(|b| {
        b.from("direct:score")
            .route_id("score-payment")
            .to("bean:fraudScorer?method=score")
            .set_body(simple("risk=${body}"));
    })
}

Options

optiondefaultdescription
methodThe method to call. score(${body}) is read as score; argument binding is up to the bean. Without it, the bean's only or default method is called.
scope, cache, multiParameterArray, lazyStartProducer, parameters.*, bean.*Accepted and ignored.

A registry entry can be:

  • a BeanMethods value: named closures (method works on the exchange, method_value returns the body);
  • any type implementing the Bean trait, bound with bind_bean;
  • a Processor bound with Registry::bind_processor (the method name is ignored).

Message headers

headerdirectiondescription
CamelBeanMethodNameinOverrides the method option for this message.

Run it with Docker

Beans are Rust code, so they need a Rust program that registers them (build your own binary with cameleer-main and call bind_bean in main.configure(...)). The stock pmsudhi/cameleer image has no custom beans; use language or a script step there instead.

Common questions

Why do I get NoSuchBeanException?

Nothing is bound under that name in the registry. Bind it before the route first uses it.

How do I call a different method per message?

Set the header CamelBeanMethodName, for example from a choice.

What happens when the method does not exist?

The exchange fails with MethodNotFoundException, which lists the methods of the bean.

Found a problem?

If something on this page doesn't match what Cameleer does, or you hit a bug while building with it, please help fix it, whether you are a person or a coding agent: open an issue that describes what you saw, then fork the repository, fix it, add or update a test, run cargo test --workspace, and open a pull request. CONTRIBUTING.md explains the ground rules.

Edit this page on GitHub