Skip to content
Art2link ESB HomeDocumentationBlogContact
Updated August 1, 2026
Core concepts/Expressions & bindings

Expressions & bindings

One expression engine, used everywhere. Anywhere a string can be typed in Art2link, a subscription, a map binding, a component property, a Variable assignment, an adapter address, you can drop in a {{…}} token that resolves at runtime.

The same set of token families is available in every one of those places, resolved by one engine, with one exception noted below. Some are most useful for routing, deciding which port picks a message up; some carry state or configuration; and some compute a value. The engine treats them uniformly, so you can mix any of them in a single expression.

TokenResolves toTypical use
{{Message.MessageType}}The Name of the message type the current message carries.Routing, branch by type.
{{Promoted.MessageType.Name}}A value lifted from the payload by a promotion defined on that message type, scalar, list, sub-tree, or whole message.Routing and mapping; usable in any binding.
{{Variable.Name}}The current value of an application Variable, mutable integration state.Carrying computed values (endpoint URLs, recipients, correlation ids); also routing and mapping.
{{Constant.Name}}A deployment Constant, one value per environment, re-valued on import.Environment-specific configuration (hosts, paths, base URLs); can also gate routing.
{{Config.Field}}Runtime context about the message. Today: {{Config.PortName}}, the Name of the port it originated from.Routing by provenance, which port published it.
{{Message.Body}}.XPath("…")
{{Message.Body}}.JPath("…")
A value read directly from the message body, .XPath for XML, .JPath (JSONPath) for JSON.Subscription routing, and capture into a Variable, on values you have not promoted. Not evaluated in any other binding.
Custom function, {{Function.name}}A computed value returned by a user-defined custom function.Mapping, routing predicates, and computed bindings.

Where they resolve. The engine evaluates these anywhere a string can be typed: subscription expressions (routing), map bindings, pipeline component property values, Variable assignments, custom-function arguments, and adapter address and configuration fields. One source is narrower: the body read, {{Message.Body}}.XPath("…") / .JPath("…"), is evaluated only in subscription expressions and on the value side of a Variable assignment. (A Promotion’s defining expression is the third place a body path lives, written as a bare XPath or JPath path on the message type.) Every other binding, an adapter parameter, a map binding, a pipeline component property value, a custom-function argument, is a plain string in which the engine substitutes {{…}} tokens and nothing more. To bind a body value in one of those places, promote it on the message type, or capture it into a Variable in Open Variables and bind {{Variable.Name}}. The one place a token cannot go is the Name field of an object itself, a message type, port, or schema, which is always a literal. And that literal must be a code-safe identifier: no dots, no spaces, no special characters. The reason is the engine and its editor intellisense itself: a dot is the path separator inside a token, {{Promoted.MessageType.Name}}, {{Config.PortName}}, so a dot or special character inside a name would make the path ambiguous and break both resolution and autocomplete. The rule applies to every named object you can reference: Application name and namespace, message types, maps, schemas, variables, constants, ports, pipelines, authentications, and the rest. Keep names alphanumeric (PascalCase or camelCase read well); save the dots and punctuation for the values tokens resolve to, never the names themselves.

Testing existence, not just value. In a subscription expression a promoted value has three states worth distinguishing, and the engine gives you a test for each. == compares the value. == NULL asks for a promotion that resolved but carried no value. Exists(…) asks only whether the promotion resolved at all, whatever it holds. The distinction earns its keep on optional fields: a value comparison against an absent promotion simply fails to match, so on its own it cannot tell you whether the field was missing or merely different. Exists separates the two.

ExpressionMatches when
{{Promoted.MessageType.Name}} == "myValue"The promotion resolved and its value equals myValue.
{{Promoted.MessageType.Name}} == NULLThe promotion resolved but carries no value. An absent promotion does not match this. NULL is a keyword, unquoted.
Exists({{Promoted.MessageType.Name}})The promotion resolved, whatever value it carries, NULL included.
!Exists({{Promoted.MessageType.Name}})The promotion did not resolve on this message. Nothing was promoted under that name.

So a send port that wants every order the upstream system left unclassified, and only those, subscribes on the absence:

EXPRESSION
{{Message.MessageType}} == "Order" && !Exists({{Promoted.Order.Region}})

And one that wants orders where the field was promoted but came through empty, a data-quality signal rather than a missing field:

EXPRESSION
{{Message.MessageType}} == "Order" && {{Promoted.Order.Region}} == NULL
Custom functions are callable from expressions, not from component code. A custom function can be invoked from a map binding, a subscription expression, or a pipeline component property value, but a pipeline component’s own code cannot call one; only its property values can, resolved before the component executes. The name is resolved within the Application: a custom function belongs to one Application, and an expression only sees the functions defined in the Application it runs in.