Payload Transformations: Brand New FreeMarker Support with WSO2 Micro Integrator 4.0.0

Nirothipan Ram
5 min readMay 5, 2021

--

Image Courtesy (source)

It has always been a trouble to match the client request (payload) format to the back end request. One would require an array of objects where as the other one will be sending a list objects with unnecessary items making the lives of developers as hard as possible. We’ve paddled and managed to do many tricks over time to overcome this.

Now, The Micro Integrator 4.0.0 release brings you an efficient and sophisticated way to achieve this with The FreeMarker support for Payload Factory Mediator.

FreeMarker is a template engine by Apache, which is Java library to generate text output based on templates and changing data. It has got many inbuilt functions helping to transform the payload as we want. Let’s explore this by trying out some real world use cases.

Following are the 3 use cases intervened in this blog with explanations

  1. Conditionally Filter out Items in Payload
  2. Count the Number of Items in Payload
  3. XML to JSON Conversion handling an array of one

Use Case I : Conditionally Filter out Items in Payload

Say we have an input payload like the one on the left which has the list of users in a JSON object and we need an output payload filtering put only the list of premium users as on the right;

Input and Output Formats

How can we achieve this with Micro Integrator elegantly ?

This can be simply accomplished using FreeMarker Support in Payload Factory mediator as follows. Following is the final synapse configuration of an API which does the above transformation and gives us the desired output.

Transformation API

Deploying and invoking the above API in Micro Integrator 4.0.0 will give you the list of premium users filtered out from the parent list and it is simple as that!

Image Courtesy (source)

Let’s look more into the template we used

What were our requirements ?

  1. Iterate over the list of users.
  2. Filter only premium users.
  3. Extract userName and mailID and map to name and e-mail.
  4. Most Importantly, add a “,” after every JSON object to preserve JSON structure but skipping only last object.

A step wise guide on how we achieved it

  1. Iterate over the list of users

FreeMarker provides an in-built elegant way to iterate over a JSON array as follows.

<#list payload.users as user>
<!--logic-->
</#list>

In here, payload is the whole input JSON object and users is the inner most element of it.

2. Filter Only Premium Users

Since the premiumUser field of input payload is just a boolean, we can directly use it in FreeMarker if condition as follows.

<#if user.premiumUser>
<!--logic-->
</#if>

What more we can do with FreeMarker If / Else conditions: Explore here.

3. Extract userName and mailID and map to name and e-mail

From the step 1, we’ve got all our user elements to the variable user and now, it is just a matter of extracting the relevant elements and mapping to our expected output.

{
"name": "${user.userName}",
"e-mail": "${user.mailID}"
}

Again, simple as that!

4. Build All these as a valid JSON

Phew… This is where I’d to use my brain a bit to add some custom logic.

The approach followed here was to have a local variable and initialize it with a value of 1 and add a “,” before each JSON element except for the time variable value is 1. This is again another variant of IF condition: you can use many other approaches as you wish.

<#assign x = 1>
<!--iteration start-->
<#if x gt 1>,</#if>
<!--logic-->
<#assign x++>
<!--iteration end-->

Combing all these logic, we get the following template.

Final Template

<![CDATA[
{
"premiumUsers": [
<#assign x = 1>
<#list payload.users as user>
<#if user.premiumUser>
<#if x gt 1>,</#if>
{
"name": "${user.userName}",
"e-mail": "${user.mailID}"
}
<#assign x++>
</#if>
</#list>
]
}
]]>

What else can this FreeMarker do ?

Including WSO2 Related Custom Properties into the payload

  • payload : The whole payload object can be referenced and navigated using this element.
Sample payload
  1. payload.userName gives the value as ram
  2. paylaod.subjects gives the list of subjects which you can iterate and do some logic based on it.
  • ctx : property is read from message context using the default scope.

ctx.message_id will try to fetch the value message_id from the synapse message context and replace it in the template.

and so on … For the full list, visit WSO2 Official Documentation.

Using switch cases within the payload

Use Case II : Count the Number of Items in Payload

Let’s implement a scenario where we count the sizes of the list of items. Assume that we’ve an input payload as on left and need an out same as the one on right;

Count Items in Payload Input and Output

Sample API Configuration to achieve this

Sample Size Counter API

The simple logic we used here is to take the item size as switch key and count the number of items. Once all are counted, we added it to the resulting payload in the intended format.

Handling Arrays with Single Element

Use Case III : XML to JSON Conversion handling an array of one

The traditional issue we’ve always experienced with XML to JSON conversion is, when there is a single element in XML it misses an enclosing array element. This is eliminated by design with the FreeMaker support for Payload Factory Mediator.

Let’s say we’ve below input payload XML:

XML to JSON Input

And we want to filter out only city names into a json array disregard of the number of cities as follows:

XML to JSON Output

We can simple achieve with the following FreeMarker code snippet.

<![CDATA[  
{
"cities": [
<#assign x = 1>
<#list payload.cities.city as city>
<#if x gt 1>,</#if>
{
"${city.name}"
}
<#assign x++>
</#list>
]
}
]]>

Here, inconsiderate about the number of of cities in the input XML, we will always get the output under a json array in cities. That is, even if we have single city in the XML, we’ll still get an array. Try it out yourself to verify.

and Many other Logical Constructs, explore as you go and need, visit Apache Directive Reference.

--

--