DataWeave (DW) has been part of the MuleSoft Anypoint Platform since v3.7.0 and has been a welcome enhancement providing an order of magnitude improvement in performance as well as increased mapping capability that enables more efficient flow design.
However, like most new features of this scope and size (i.e. brand new transformation engine written from the ground up), early documentation was minimal and often we were left to ourselves. At times even the most simple mapping scenarios could take an hour or so to solve what could have taken 5 mins in data-mapper. But it pays to stick with it and push on through the adoption hurdle as the pay offs are worth it in the end.
For those starting out with DataWeave here are some links to get you going:

In this post I will share some tips and tricks I have picked up from the field with the aim that I can give someone out there a few hours of their life back.

Tip #1 – Use the identity transform to check how DW performs it’s intermediate parsing

When starting any new DW transform, it pays to capture and understand how DW will parse the inputs and present it to the transform engine. This helps navigate some of the implicit type conversions going on as well as better understand the data structure being traversed in your map. To do this, start off by using the following identity transform with an output type of application/dw.

Previewing a sample invoice xml yields the following output which gives us insight into the internal data structure and type conversations performed by DW when parsing our sample payload.

and the output of the identity transform

Tip #2 – Handling conditional xml node lists

Mule developers who have being using DW even for a short time will be used to seeing these types of errors displayed in the editor

Cannot coerce a :string to a :object

These often occur when we expect the input payload to be an array or complex data type, but a simple type (string in this case) is actually presented to the transform engine. In our invoice sample, this might occur when an optional xml nodelist contains no child nodes.

To troubleshoot this we would use the identity transform described above to gain insight into the intermediate form of our input payload. Notice the invoices element is no longer treated as a nodelist but rather a string.

We resolve this by checking if ns0#invoices is of type object and provide alternative output should the collection be empty.

Tip #3 – Explicitly setting the type of input reader DataWeave uses

Occasionally you will hit scenarios where the incoming message (input payload) doesn’t have a mimeType assigned or DW cannot infer a reader class from the mimeType that is present. In these cases, we’ll either get an exception thrown or we may get unpredictable behaviour from your transform. To avoid this, we should be in the habit of setting the mimeType of the input payload explicitly. At present we can’t do this in the graphical editor, we will need to edit the configuration xml directly and add the following attribute to the <dw:input-payload> element of our transform shape
[code language=”xml” gutter=”false”]
<dw:input-payload doc:sample="xml_1.xml" mimeType="application/xml" />
[/code]

Tip #4 – Register custom formats as types (e.g. datetime formats)

Hopefully we are blessed to be always working against strongly typed message schema where discovery and debate over the data formats of the output fields never happen…yeah right. Too often we need to tweak the output format of data fields a couple of times during the development cycle. In large transforms, this may mean applying the same change to several fields throughout the map, only to come back and change this again the next day. To save you time and better organise your DW maps, we should look to declare common format types in the transform header and reference those throughout the map. If we need to tweak this we apply the change in one central location.

Tip #5 – Move complex processing logic to MEL functions

Sometimes even the most straight forward of transformations can lead to messy chains of functions that are hard to read, difficult to troubleshoot and often error prone. When finding myself falling into these scenarios I look to pull out this logic and move it into a more manageable MEL function. This not only cleans up the DW map but also provides opportunity to place debug points in our MEL function to assist with troubleshooting a misbehaving transform.
Place your MEL function in your flow’s configuration file at the start along with any other config elements.

Call your function as you would if you declared it inline in your map.

Tip #6 – Avoid the graphical drag and drop tool in the editor

One final tip that I find myself regularly doing is avoid using the graphical drag and drop tool in the editor. I’m sure this will be fixed in later versions of DataWeave, but for now I find it creates untidy code that I often end up fighting with the editor to clean up. I would only typically use the graphical editor to map multiple fields en-mass and then cut and paste the code into my text editor, clean it up and paste it back into DW. From then on, I am working entirely in the code window.
There we go, in this post I have outlined six tips that I hope will save at least one time poor developer a couple of hours which could be much better spent getting on with the business off delivering integration solutions for their customers. Please feel free to contribute more tips in the comments section below.

Category:
Mulesoft
Tags:
, ,

Join the conversation! 1 Comment

  1. Hi, I’ve been fighting with a “cannot coerce array to object” error when trying to transform a JSON payload with arrays to an XML body with node lists having child element names that the JSON doesn’t specify. I know I’m shooting in the dark as your post is a couple years old – but I hope you can help out a fellow traveler. Mulesoft forums have not been helpful for this.

    val
    val

    valy
    valx


    where the json looks like:

    “parent” : [
    { prop:”val”, propN:”val”},
    { prop:”valy”, propN:”valx”}
    ]

    This scenario happens at various levels in many of the json bodies I transform. I dislike the very hardcoded results of the UI mapper from one payload to another and I want something a little more dynamic than this, something like a when/otherwise solution. I had the same challenges when going from XML to JSON and wanting to clean up a node list. I use the following:

    ——–
    %dw 1.0
    %input payload text/xml
    %output text/json
    %namespace ns0 https://namespace.com

    payload.Envelope.Body.LevelOne.LevelTwo mapObject {
    ($$) :
    $.*workDetail when $$ ~= ‘workDetails’
    otherwise (
    $.*errorInfoList when $$ ~= ‘errorInformation’
    otherwise (
    $
    )
    )
    }
    ——–

    I want something similar for the previously mentioned JSON to XML issue I mentioned. A simple when/otherwise, or an elegant solution that basically says: If this element is of name ‘Parent’, then make it and node list of . I’m ok with hard-coding the name of ‘Parent’ whatever it may be partly because I have to specify the child element name since the JSON doesn’t have it present.

    I appreciate anything you can offer me, there seem to be these humps I just can’t quite get over. Thanks for your help.

Comments are closed.