JavaScript language
The
jslanguage evaluates JavaScript expressions and scripts against the message, withbody,headersandexchangeavailable as variables.
Name: js · Also: javascript, javaScript · Crate: cameleer-script · Cargo feature: script ·
Apache Camel: JavaScript
When to use it
- Reshape a JSON answer from an LLM or an API with a few lines of code (
JSON.parse,map,filter,JSON.stringify) where Simple or JSONPath gets awkward. - Route on a computed condition in
filterorchoice. - Run a small script step that sets several headers at once.
Syntax
Cameleer runs JavaScript in its own interpreter, written in Rust. It is not GraalJS or V8 and
does not need a JVM. It covers ES5.1 plus most of ES2015-2023 as used in route scripts: let and
const, arrow functions, template literals, destructuring, spread, classes, optional chaining
?., ??, Map and Set, generators, Promise and async/await (drained before the
result is returned), JSON, Math, Intl for a few locales. There is no Node.js API
(require('fs'), process, network access), and no access to Java classes beyond a few safe
JDK types through Java.type.
Variables available to the script:
| variable | what it is |
|---|---|
body | the message body (a string body stays a string: use JSON.parse(body) for JSON text) |
headers | the message headers: headers.get('name') or headers.name |
request, message | the message: request.body, request.headers.name, request.setHeader(k, v) |
exchange | the exchange with Java-like accessors: exchange.getIn().getHeader('x'), exchange.setProperty(k, v) |
properties, exchangeProperties | the exchange properties |
variables | the exchange variables |
camelContext | the context (camelContext.getName()) |
log | a logger (log.info('...')) |
The value of the last expression statement is the result. Used as an expression (in setBody,
setHeader, filter...) the script works on a copy of the message and only its result counts.
In a script step the result is ignored and its changes to body, headers, properties and
variables are kept.
Examples
Reshape an LLM's JSON answer
The model answered with JSON text. Keep only confident labels and build a compact routing decision.
- route:
id: js-reshape
from:
uri: direct:js-reshape
steps:
- setBody:
js: |
const answer = JSON.parse(body);
const labels = answer.labels.filter(l => l.score >= 0.5).map(l => l.name);
JSON.stringify({ ticket: answer.id, labels, urgent: labels.includes('outage') });{"id":"T-17","labels":[{"name":"billing","score":0.2},{"name":"outage","score":0.93},{"name":"eu","score":0.71}]}{"ticket":"T-17","labels":["outage","eu"],"urgent":true}Route with a JavaScript predicate
- route:
id: js-choice
from:
uri: direct:js-choice
steps:
- choice:
when:
- js: "headers.get('amount') > 1000"
steps:
- setBody:
constant: needs approval
otherwise:
steps:
- setBody:
js: "'auto-approved: ' + headers.get('amount')"orderneeds approvalorderauto-approved: 40A script step that changes the message
- route:
id: js-script
from:
uri: direct:js-script
steps:
- script:
js: |
const words = body.trim().split(/\s+/);
request.setHeader('wordCount', words.length);
request.body = words.map(w => w[0].toUpperCase() + w.slice(1)).join(' ');
- setBody:
simple: "${body} (${header.wordCount} words)"send messages to kafkaSend Messages To Kafka (4 words)Expressions
Evaluated against this message:
{"body": "hello", "headers": {"amount": 250, "name": "Ada"}, "properties": {"region": "eu"}, "variables": {"user": "ada"}}| expression | result |
|---|---|
body.toUpperCase() | HELLO |
headers.get('amount') > 100 | true |
request.headers.name + '!' | Ada! |
exchange.getIn().getHeader('name') | Ada |
`Hi ${headers.get('name')}` | Hi Ada |
[1, 2, 3].map(x => x * 2).join(',') | 2,4,6 |
properties.region | eu |
variables.user | ada |
typeof body | string |
Options
| option | default | description |
|---|---|---|
resultType | (none) | Convert the result to this type (int, String, boolean...). |
scriptDir | (none) | Directory that relative ES module imports resolve against. |
Rust DSL
b.from("direct:js-rust")
.set_header("len", cameleer_script::js("body.length"))
.set_body(cameleer_script::js("body.toUpperCase()"));Common questions
How do I parse a JSON body in JavaScript?
A JSON text body is a string, so call JSON.parse(body). If an earlier step already
unmarshalled the body (for example unmarshal: json), body is an object and body.field works
directly.
How do I change headers from a script?
Use a script step and call request.setHeader('name', value) or
exchange.getIn().setHeader(...). In setBody or setHeader the script runs on a copy, so
other changes are discarded.
Can I use npm packages or Node.js modules?
No. The interpreter has no Node.js runtime. Local ES modules can be imported relative to
scriptDir.
Related
- Groovy, Python and Java script languages.
- Simple language for one-line templates, JSONPath and jq for picking fields from JSON.
- JSON data format.
- Apache Camel JavaScript language
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.