In the first part of this series we tackled the issue of defining and also using variables within DataWeave as opposed to using the legacy set “Variable” module. Today, I need to raise the topic of functions in DataWeave as a key thought when working with MuleSoft has to be “can I reuse this?”
Much like the case for not using the legacy components in a flow, when better options exist in DataWeave, the same holds true for defining re-usable functions within DataWeave. If we can define a function for a piece of transformation that is used in multiple places, it will not only give us a cleaner and more compact DataWeave script but will also mean we only have to make changes in one place.
The most common place I have seen the need for a function is within a DataWeave script where we need to perform the same transform on a number of different fields.
A simple example of a function might be to take a field of “lastname, firstname” and split it into the requisite parts, for example our incoming payload could contain:
{ "name" : "smith, john" }
Our DataWeave script looks like:
%dw 1.0 %output application/json %function toUser(user) {firstName: (user splitBy ",")[0], lastName: (user splitBy ",")[1]} --- { "user" : toUser(payload.name) }
We declare a function in the DataWeave header with the use of “%function”, we then define the function name and the input syntax. Our function is called “toUser()” and we declare that it will take in a single string field of “user”, this is represented as “toUser(user)”. Now that we have our function declared, we can implement whatever logic is necessary. In our case, we are doing a simple “splitBy” to split the incoming name into first name and last name. The resulting output is:
{ "user": { "firstName": "smith", "lastName": " john" } }
Obviously, this is a simple example but the ability to reuse this function within a single DataWeave script is unlikely. So let us take a look at a more realistic, real-world example.
Recently I worked with a customer that was calling a REST API that returns a JSON body to a request. This JSON body contains data about a user’s interests and some content information that required some non-trivial transformation performed.
The values we are looking to extract are contained in the “tags” and “contenttypes” arrays nested under the array of “interests”:
{ "interests": { "tags": [ "pharmaceuticals:Pharmaceuticals", "public-health:Public Health" ], "contenttypes": [ "insights:Business Insights", "predictions:Predictions" ] } }
In order to tackle this transformation, we need to do two things. First, split the values in the arrays as we want the value to the left of the colon and, second, flatten the array objects into a string.
We start by declaring our splitting function and we will call it “splitByColon”.In this function we will use some DataWeave to split the string object passed into the function by “:” then we will select the first item in the split. Split produces an array of values so we use our array selector to pick off the first value, this results in the following DataWeave script:
%dw 1.0 %input payload application/json %output application/json %function splitByColon(data) (data splitBy ":")[0] --- { }
Our split function is expecting a string value to split, so we need a way to access each item in the array to pass to the split function. Thankfully the reduce function provides us with this and we need to perform a reduction anyway:
%dw 1.0 %input payload application/json %output application/json %function splitByColon(data) (data splitBy ":")[0] %function reduceToString(data) data reduce (splitByColon($) ++ " " ++ splitByColon($)) --- { }
In our “reduceToString” function, we reference the “splitByColon” function, we are splitting each value in the array, then performing a concatenation of each result from the “splitByColon” as defined by the reduction.
Now we just need to define the output structure and feed our input payload arrays into the “reduceToString” function:
%dw 1.0 %input payload application/json %output application/json %function splitByColon(data) (data splitBy ":")[0] %function reduceToString(data) data reduce (splitByColon($) ++ " " ++ splitByColon($)) --- { tags: reduceToString(payload.interests.tags), types: reduceToString(payload.interests.contenttypes) }
The result is a clean and readable DataWeave transform script thanks to the functions; it also generated the output we needed:
{ "tags": "pharmaceuticals public-health", "types": "insights predictions" }
Anytime we are performing the same transformation on multiple values, a function will make our DataWeave script easier to read, support and troubleshoot.
In the next article in this series, we will address the oft-seen need to perform nested looping through arrays of values to find the data we need.