It is always desirable to reuse as much code as possible. We can do the same regarding to DataWeave transformations and custom functions. In this article I will describe how to reuse code in newest DataWeave using modules. For those of you, working with DataWeave 1.0, I will describe how to reuse code with readUrl function.

DataWeave Module

With newest Mule 4 we got a lot of new improvements. The same is with DataWeave 2.0. MuleSoft has introduced modules concept. All functions prepared by Mule team have been divided into logical pieces and placed within modules as in the diagram below.

DataWeave Modules

Core module is the special one. This module is imported by default in your transformations. In contract, other modules you need to import explicitly. All modules and their functions are fully described at MuleSoft documentation page.

Implementation

Custom modules are separate dwl files.You mainly place them in src/main/resources/dw folder. However you can use the package name whatever you like for example modules/json/utils.  

Your custom module may contain only:

  • variable declaration – var
  • functions – fun
  • namespace declaration – ns
  • custom types – type

In such file, output directive is not permitted, as well headers-body separator .  Because the custom module file contains only body. Below you can see example sample DataWeave file.

%dw 2.0

ns blogns https://profit-online.pl/blog
var protocol = "https"

fun appendURL(url: String) =
	protocol ++ "://" ++ url ++ "/test"

Let’s see what is going on there. First we have DataWeave version declaration – %dw 2.0. This is the only directive with percent sign. Then we have blogns namespace defined. In fourth line we have protocol variable that is used later on in appendURL function. This function concatenate string to nice URL. Let’s compare it with standard tranformation.

%dw 2.0
output application/json skipNullOn="everywhere"
---
{
	userAge: payload.age
}

In the transformation we have output directive. In contract custom module doesn’t have such declaration.  What is more, in transformation we have headers-body separation, whereas in module we do not have.

Ok, so we have defined our own custom module. How to use it?

Usage

In order to use functions, variables, etc defined in any module, we have import directive. It can be used in two different ways:

  • whole module import,
  • import specific parts from the module.

Here, how it looks in code:

  • import dw::core::Arrays
  • import * from dw::core::Arrays
  • import countBy, sumBy from dw::core::Arrays

First two examples import the whole content defined in Arrays module. The last one, on the other hand, import only two functions by name. Imagine that I have put my filter.dwl file in src/main/resources/dw1/json/utils. How should I import it?

import dw1::json::utils::filter

As you can see the structure is the same as directory tree, but instead of slash we use double colons. 

After import, we would like to use it. When we did not specify what functions to import we refer to them by module name. Let’s see example with the Arrays module.

%dw 2.0
output application/json skipNullOn="everywhere"
import dw::core::Arrays
---
Arrays.countBy($ > 2)

In case of importing specific function from the module we do not need to use module name. Like in the example below.

%dw 2.0
output application/json skipNullOn="everywhere"
import countBy, sumBy from dw::core::Arrays
---
countBy($ > 2)

Reuse in DataWeave 1.0

In previous version of DataWeave reusability was possible by loading file from the classpath by using readUrl function. So, how to share DataWeave transformation?

Implementation

Unlike DataWeave 2.0, file should have headers and body sections separated by three dashes. In the header section you may implement functions, create variables and declare namespace.

%dw 1.0

%namespace blogns https://profit-online.pl/blog
%var protocol = "https"

%function appendURL(url)
	protocol ++ "://" ++ url ++ "/test"

---
{
	appendURL: appendURL,
	blogns: blogns
}

In the example above, in our library are defined:

  • appendURL function,
  • protocol variable with value “https”,
  • namespace.

In the body section we need to declare what will be accessible outside the library. We do this, by defining an object with properties and assigned references to the function/variable/namespace. 

Function by reference

Like in JavaScript, and other programming languages, you may pass function as an argument. This passed argument can be invoked later on by the caller.

Have you notice what is missing in the mapping file, above? Yes, you are right we do not provide %output directive.

Usage

In order to load DataWeave file use readUrl function. It takes only one argument. It is a URI to resource. URI contains two parts. First is the protocol. Mainly it is classpath. The second part is the path to the dwl file.

%dw 1.0
%output application/json skipNullOn="everywhere"

%var filterLib = readUrl("classpath://dw1/json/utils/emptiness_filter.dwl")

---
filterLib.filterEmptyObjects({"myprop1": "super value", "obj": { }})

In the example we are loading emptiness_filter.dwl file from classpath located in the dw1/json/utils folder.

Summary

I like new idea of Modules in DataWeave 2.0. Modules are similar to Java packages concept and make managing code easier. We are able, to create custom modules. In contrast to DataWeave 1.0 we are not able to decide what should be accessible outside of the file. So module will publish its full content. In that case, some parts can be rewritten so that only desired parts are exported.

If you have reusable pieces of code. Extract it to external file. If this is something that can be shared for more than one project, you can embed files into a jar and share it among projects. In that scenario you use code the same way as described above.

Tagged on:             

Leave a Reply

Your email address will not be published. Required fields are marked *