Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

DataWeave Tip #8: The write Function

DZone's Guide to

DataWeave Tip #8: The write Function

Learn about the 'write' function in Mule and how to apply it to allow your applications to properly communicate with various HTTP endpoints.

· Integration Zone ·
Free Resource

WSO2 is the only open source vendor to be named a leader in The Forrester Wave™: API Management Solutions, Q4 2018 Report. Download the report now or try out our product for free.

Recently I have been working on a really simple case. When an HTTP server returned an error and a non-empty body, I needed to embed this body into an error structure. Although this is a simple case, I got a problem with implementing it in Mule 4. In the previous Mule edition, it was a little bit simpler. So let's see what it is all about.

Case

First, we have a look at the case that I have to implement. I have a mule application that is calling an external HTTP server via an HTTP request component. When the server responds with an error like 4xx, 5xx, and the returned body will is not empty, we would like to forward that response to the calling application.

In the diagram below, I have depicted a situation where an HTTP server sent a 400 Bad request response back to our application. Then I attach returned the body to my custom error response structure that will be returned to the calling application.

When we receive an error response, it may happen that not all of them will have the same content type. Here are three examples:
400 Bad Request:
{
  "errors": [
    {
      "status": "400",
      "title":  "Invalid Attribute",
      "detail": "First name must contain at least three characters."
    }
  ]
}

500 Internal Server Error:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><myErrorEnvelope>
  <internalCode>123</internalCode>
  <description>error details</description>
</myErrorEnvelope>

404 Not Found:

"Not Found"

I would like to return to my client following response:

{
  "code":  "{{my custom title}}",
  "description": "{{detailed description}}",
  "content": "{{response body returned by the HTTP server}}"
}

Design

Simple Assignment

I could simply assign the returned content like in the script below. As you can see, the field content will have a returned payload. As it is described in this article, exceptions are packed into an error object. The response that the HTTP request component received will be packed into the errorMesage property of the error object.

%dw 2.0
output application/json
---
{
code: error.errorMessage.attributes.statusCode,
description: "Description",
content: error.errorMessage.payload
}

This solution is a simple one, however, the DataWeave transform component will translate the error response into a JSON format. If we do not care to see the original response, this may be a good solution. In my case, I need to see the exact response in the format returned by the server. That is how I found out about the write funtion.

Write Function

The write function is designed to convert an incoming object into a text string. The function's signature is as follows:

write(object: Any, format: String, conf: Object): String

Arguments:

  • object to write. Any type is acceptable. It may be an xml document, json, plain text etc.
  • Output format. Only types supported by DataWeave. By default, application/dw is used.
  • Additional configuration: conf.

In the diagram below, you can find three sample cases. In all cases, we would like to have a written payload in XML. In the first case, we have an XML document as an input. The write function takes it and transforms it into an XML string.

The second case has a JSON input with one root property. The write function takes it and transforms it into an XML string. Transformation works here because JSON has one root property and XML expects that.

The third case has a JSON input with two properties on the root level. The write function tries to transform it, however, it would result in a malformed XML document. Therefore it throws an error.

So here I have the transformation when the write function is used. As you can see, I have applied the content type to be application/xml.
%dw 2.0
output application/json
---
{
code: error.errorMessage.attributes.statusCode,
description: "Description",
content: write(error.errorMessage.payload, "application/xml")
}

The write function does expect that the supplied object is XML. Here is a sample output of that transformation.

{
  "code": 400,
  "description": "Description",
  "content": "<?xml version='1.0' encoding='windows-1252'?>\n<root>\n  <message>Bad request</message>\n</root>"
}

Okay, but I forgot to tell you earlier that I can expect different payload types. What can I do?

How about changing the type to text/plain? It would be the most generic option. But, sadly, it won't work. DataWeave will return an error, for example, the application/json object can't be transformed into text/plain.

In order to fix this, we need to place a component, such as Set Payload or Set Variable, and set its mimeType attribute to the value's text/plain. After that it will work smoothly.

So here is the final transformation:
%dw 2.0
output application/json
---
{
code: error.errorMessage.attributes.statusCode,
description: "Description",
content: write(payload, "text/plain")
}

Summary

Thewrite function is very helpful and I found out that it may be useful in a variety of places during application design. I found it a bit problematic that it performs also validation so when I have received invalid data this function will throw an error.

See you soon!

IAM is now more than a security project. It’s an enabler for an integration agile enterprise. If you’re currently evaluating an identity solution or exploring IAM, join this webinar.

Topics:
integration ,mule ,http endpoints ,http server ,server requests

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}