Mustache component
The
mustachecomponent renders a Mustache template against the message (body, headers, properties) and sets the rendered text as the new body.
Scheme: mustache: · Crate: cameleer-core · Cargo feature: templates · Consumer: no · Producer: yes ·
Apache Camel: Mustache
When to use it
- Build an LLM prompt from a JSON request: fill a prompt template with the user's question and context documents before calling a model.
- Render an email, a Slack message or a report from structured data.
- Produce a text payload (CSV line, SQL, XML snippet) without code.
- Keep wording in a file that non-developers can edit, separate from the route.
URI format
mustache:templateResource[?options]templateResource is a file path relative to the working directory, file:path,
classpath:path (read as a relative path, there is no classpath) or ref:beanName (a
String bound in the registry).
Example
A support agent receives {"customer": ..., "question": ..., "docs": [...]} and turns it into
a prompt for a model. The body is unmarshalled from JSON first so the template can read its
fields.
You are a support assistant for {{headers.product}}.
Customer: {{body.customer}}
Question: {{body.question}}
{{#body.docs}}
- {{title}}: {{text}}
{{/body.docs}}
{{^body.docs}}
No documents matched.
{{/body.docs}}
Answer in at most {{headers.maxWords}} words.- route:
id: mustache-prompt
from:
uri: direct:mustache-prompt
steps:
- unmarshal:
json: {}
- setHeader:
name: product
constant: Cameleer
- setHeader:
name: maxWords
constant: "80"
- to: mustache:templates/support-prompt.mustache{"customer":"Ada","question":"How do I retry a failed HTTP call?","docs":[{"title":"Error handling","text":"Use onException with maximumRedeliveries."},{"title":"HTTP","text":"Set throwExceptionOnFailure=true."}]}You are a support assistant for Cameleer.
Customer: Ada
Question: How do I retry a failed HTTP call?
- Error handling: Use onException with maximumRedeliveries.
- HTTP: Set throwExceptionOnFailure=true.
Answer in at most 80 words.With no documents, the inverted section renders instead:
{"customer":"Bo","question":"Is there a Kafka component?","docs":[]}You are a support assistant for Cameleer.
Customer: Bo
Question: Is there a Kafka component?
No documents matched.
Answer in at most 80 words.Template from a header
With allowTemplateFromHeader=true the CamelMustacheTemplate header replaces the template
file, so a route can render templates stored elsewhere (a database, a config service).
{{...}} inside a route file is a property placeholder, so a template written in the route
itself uses other delimiters (startDelimiter / endDelimiter). Template files are not
affected.
- route:
id: mustache-header
from:
uri: direct:mustache-header
steps:
- setHeader:
name: CamelMustacheTemplate
constant: "Hello [[body]]!"
- to:
uri: mustache:templates/support-prompt.mustache
parameters:
allowTemplateFromHeader: true
startDelimiter: "[["
endDelimiter: "]]"WorldHello World!Rust DSL
b.from("direct:mustache-rust")
.to("mustache:templates/support-prompt.mustache?contentCache=true");Options
| option | default | description |
|---|---|---|
allowTemplateFromHeader | false | Use the CamelMustacheTemplate / CamelMustacheResourceUri headers when present. |
contentCache | false | Read the template once and keep it; otherwise it is re-read for every message. |
allowContextMapAll | false | Add camelContext (with name) to the data model. |
startDelimiter | {{ | Opening tag delimiter. |
endDelimiter | }} | Closing tag delimiter. |
encoding | UTF-8 | Accepted; templates are always read as UTF-8. |
Data model
| name | value |
|---|---|
body | the message body (an object after unmarshal: json, so body.field works) |
headers | the message headers (headers.name) |
variables | the exchange variables |
exchange | exchange.properties, exchange.exchangeId, exchange.pattern, exchange.message |
request, in | body, headers, messageId of the message |
camelContext | camelContext.name, only with allowContextMapAll=true |
Supported Mustache features
Escaped {{name}} and unescaped {{{name}}} / {{& name}} variables, dotted names, the
implicit iterator {{.}}, sections over lists, objects and booleans, inverted sections
{{^x}}, comments {{! ... }}, partials {{> name}} (loaded from the template's directory as
name or name.mustache), set-delimiter tags {{=<% %>=}} and standalone-line removal.
Lambdas are not supported.
Message headers
| header | direction | description |
|---|---|---|
CamelMustacheTemplate | in | Template text used instead of the endpoint's resource (needs allowTemplateFromHeader=true). Removed after use. |
CamelMustacheResourceUri | in | Template resource used instead of the endpoint's one (needs allowTemplateFromHeader=true). |
Run it with Docker
Put the route in prompt.camel.yaml and the template in templates/ next to it:
docker run --rm -v "$PWD:/routes:ro" pmsudhi/cameleer run /routes/prompt.camel.yamlThe image's working directory is /routes, so templates/support-prompt.mustache resolves to
the mounted file.
Common questions
How do I read JSON fields in a Mustache template?
Unmarshal the body first (unmarshal: json: {}); then {{body.field}} and sections over
body.list work. A plain JSON string body has no fields.
Why does {{body.text}} turn < into <?
Double braces HTML-escape the value, as in every Mustache implementation. Use {{{body.text}}}
or {{& body.text}} for raw text, which is what you want for prompts and plain text.
Why do I get "Property with key [x] not found"?
The template text is inside the route file, where {{x}} is a property placeholder resolved
when the route starts. Keep templates in files, or switch delimiters with startDelimiter and
endDelimiter as in the header example above.
Does the template reload when I edit the file?
Yes, by default the file is read for every message. Set contentCache=true to read it once.
Related
- FreeMarker, Velocity, StringTemplate, MVEL: other template engines.
- JSON data format: unmarshal JSON before rendering.
- Apache Camel Mustache component
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.