Message Enricher

One common scenario involves the need to enrich an incoming message with information that isn’t provided by the source system. You can use a content enricher if the target system needs more information than the source system can provide.

Consider a message from a source system contains a zip code but the target system needs the two letter state. A message enricher can be used to lookup the state using the zip code from an enrichment resource. The enricher calls out to the enrichment resource with the current message (containing the zip code) then enriches the current message with the result.

<flow name="orderProcessingFlow">
   <inbound-endpoint ref="orderEndpoint"/>
   <enricher target="#[variable:state]">
       <outbound-endpoint ref="stateLookup"/>
   </enricher>
   <outbound-endpoint ref="orderStep2"/>
</flow>

This is a very simple flow with one-way inbound and outbound endpoints, and which acts as part of an order processing pipeline. This flow uses an enricher to add a state flow variable to the current message with the state that the stateLookup endpoint returns. The ‘target’ attribute defines how the current message is enriched using a MessageEnricher which uses the same syntax as expression evaluators.

Notes:

  • Mule currently supports enrichment of flow variables and message headers only.

  • Even though the Message Enricher receives a copy of the Mule message, the payload is not copied. In other words, if the payload of your message is a mutable object (for example a bean with different fields in it) and a message processor in your Message Enricher changes the value of one of the fields, the message processors outside of the Message Enricher only see the changed values.

More Complex Enrichment

In this particular example the 'addressLookup' endpoint receives the full message, in some cases this might be a generic service that doesn’t know how to parse our order message but rather just a zip string. It is very easy to improve the configuration to support this, consider the following snippet:

<flow name="orderProcessingFlow">
   <inbound-endpoint ref="orderconnector"/>
   <enricher target="#[variable:address]">
       <outbound-endpoint ref="addressLookup">
           <expression-transformer evaluator="xpath" expression="/order/address/zip" />
       </outbound-endpoint>
   </enricher>
   <outbound-endpoint ref="orderStep2"/>
</flow>

The “enrichment resource” can be any message processor, outbound connector, processor-chain or flow-ref. If using an outbound-connector then of course it should have a request-response exchange pattern.

More Advanced Examples

The enricher element also supports more advanced use cases where the message returned by the enrichment resource isn’t just a simple string which is exactly what we need to enrich the current message with, often you may want to enrich your message with just part of the information from the result of the invocation of an external service.

For example, if you have a requirement to validate the credit card used for the order as well as add the full address using the ZIP code. The credit card validation process should populate a header call “paymentValidated” with either true or false, this will be used later on. We can easily perform credit card validation by calling out to an authorization service like Authorize.Net to perform this validation, but we have a problem this cloud connector returns more than just a boolean.

The solution is to use the enrichers ‘source‘ attribute which will select a value from the result message before using it to enrich the target.

<flow name="orderProcessingFlow">
   <inbound-endpoint ref="orderconnector"/>
   <enricher target="#[variable:paymentValidated]" source="/authorizenet/authorization/@valid">
       <authorizenet:authorize cardNumber="/order/cc/number" />
   </enricher>
   <outbound-endpoint ref="orderStep2"/>
</flow>

This approach allows you to map content in the response message from the enrichment resource to the current message. If you have a more advanced use case you can also map n values in the enrichment resource response to m values enriched in the current message, this is done using child enricher elements each of which has source and target attributes. Note: if you use child enricher elements the source/target attributes on enricher are not allowed.

<flow name="orderProcessingFlow">
   <inbound-endpoint ref="orderconnector"/>
   <enricher>
       <authorizenet:authorize cardNumber="/order/cc/number" />
       <enrich target="#[variable:paymentValidated]" source="/authorizenet/authorization/@valid" />
       <enrich target="#[variable:paymentAuthCode]" source="/authorizenet/authorization/code"/>
   </enricher>
   <outbound-endpoint ref="orderStep2"/>
</flow>

Variables and Enrichers

You can make the source a namespace by simply populating the field with a Mule Expression Language MEL expression, for example with an xpath expression that takes arguments from the Mule message.

You can find information on using a variable with any enricher listed on these pages:

Mule XML Example

The Mule flow in the following example shows how to use a Message Enricher (<enricher/>) to modify content of a Mule variable. It uses Set Variable to set the initial value of the Mule variable called greeting. It also shows how to use Set Variable and Transform Message to enrich the value of greeting and how to pass the value of the Mule variable to the payload. In addition, it demonstrates differences between the scope of a payload and variable that are defined or modified within the scope of the Processor Chain.

<http:listener-config name="HTTP_Listener_Config" host="0.0.0.0" port="8081" doc:name="HTTP Listener Configuration"/>
<flow name="enrich-message">
	<http:listener config-ref="HTTP_Listener_Config" path="/hello" doc:name="HTTP"/> (1)
	<set-variable variableName="greeting" value="Hello" doc:name="Set Outer Variable"/> (2)
	<logger message="#['Initial Greeting: ' + flowVars.greeting]" level="INFO" doc:name="Log Initial Greeting"/> (3)
	<enricher target="#[flowVars.greeting]" source="#[flowVars.greeting + '!!!']" doc:name="Message Enricher"> (4)
		<processor-chain doc:name="Processor Chain"> (5)
			<set-variable variableName="greeting" value="#[flowVars.greeting + ' World']" doc:name="Set Inner Variable"/> (6)
			<dw:transform-message doc:name="Transform Message: Change greeting Variable"> (7)
			   <dw:input-payload mimeType="application/java" /> (8)
				<dw:set-variable variableName="greeting">
           <![CDATA[%dw 1.0
%output application/java
---
"Oh, " ++ flowVars.greeting ++ " Traveler"]]></dw:set-variable>
			</dw:transform-message>
			<set-payload value="#['some arbitrary payload']" doc:name="Set Inner Payload"/> (9)
      <logger message="#[payload]" level="INFO" doc:name="Log Inner Payload"/> (10)
		</processor-chain>
	</enricher>
	<logger message="#[payload]" level="INFO" doc:name="Log Payload (null)"/> (11)
	<logger message="Final greeting value: [#[flowVars.greeting]]" level="INFO" doc:name="Log Outer Variable"/> (12)
	<set-payload value="#[flowVars.greeting]" doc:name="Set Payload (to value of greeting variable)"/> (13)
	<logger message="#[payload]" level="INFO" doc:name="Log Final Payload"/> (14)
</flow>
1 HTTP listener is configured to trigger the flow with localhost:8081/hello.
2 Set Variable sets the initial value of the outer greeting variable to "Hello".
3 Logger prints a message with the value of the outer greeting variable, Initial Greeting: Hello.
4 Message Enricher adds exclamation points to greeting by setting source to #[flowVars.greeting + '!!!'].
5 Components within Processor Chain modify greeting and set an arbitrary payload value.
6 Within the Processor Chain component, Set Variable creates a 'greeting' variable that appends a string to the original 'greeting' variable: flowVars.greeting + ' World'.
7 Transform Message adds text around the inner 'greeting' variable: 'Oh, ' + greeting + ' Traveler'.
8 Transform Message also adds a MIME type for the input payload, which avoids the message MimeType was not resolved '/' delegating to Java.
9 Set Payload sets an arbitrary payload value, some arbitrary payload, which applies within the context of the enricher. Unlike a Mule variable, the scope of this Mule payload is limited to the Processor Chain.
10 Logger within Processor Chain prints a message with the inner payload: some arbitrary payload.
11 Logger outside the scope of Processor Chain prints a message with the value of the outer payload, null.
12 Logger prints a message that includes the final greeting variable, Oh, Hello World Traveler!!!. The full message is 'Final greeting value: [Oh, Hello World Traveler!!!]' because the message field is set to "'Final greeting value: [#[flowVars.greeting]]'".
13 Set Payload uses #[flowVars.greeting] to set the value of the final greeting variable (Oh, Hello World Traveler!!!) as the payload.
14 Logger prints the final payload, Value of payload: Oh, Hello World Traveler!!!.

Was this article helpful?

💙 Thanks for your feedback!

Edit on GitHub