Mule Dataweave: How to dynamically map HTTP response(JSON) to XML output - mule

I am building an application, where I have to hit a restful interface, and pass a specific section of the response to the UI.
The response model is quite huge with a lot of fields(String, array of objects, object,number datatypes), so using manual transformation is a big pain.
Is there a way to map the section of the response to a variable and directly send it to the UI.
I tried,
%dw 2.0
%output application/xml
%var UserAcct= payload.UserResponse.UserDetailsResp.UserAccounts
---
{
User: {
"UserAccount": {
Account: UserAcct
}
}
}
This doesn't work because, the payload has List, Array of Objects etc in the response and mapping to a variable throws an error. Is it possible to send the section payload.UserResponse.UserDetailsResp.UserAccounts directly in dataweave?? Please help.

It will be more helpful if you add Input payload, error and XML output.
Following is the code just by assuming your scenario. You can give this a try:
%dw 2.0
output application/xml
---
{
User: {
"UserAccount": {
(payload.UserResponse.UserDetailsResp.UserAccounts map {
Address:{
<XMLFieldName>: $.<respectiveJSONFieldToMap>
....
}
})
}
}
}

Related

Import xml namespace from custom Dataweave module

I'm trying to create a custom Dataweave module for centralizing my custom XML namespaces.
I followed the official document of Mulesoft:https://docs.mulesoft.com/mule-runtime/4.3/dataweave-create-module
it states that: "When you import a custom module into another DataWeave script, any functions, variables, types, and namespaces defined in the module become available for use in the DataWeave body".
So I was expecting that I could create a module (in modules folder) containing my namespaces like this: Namespaces.dwl
ns myNs1 http://namespaces/my1
ns myNs2 http://namespaces/my2
import that module in another Dataweave like this:
%dw 2.0
import * from modules::Namespaces
output application/java
---
{
body: {
myNs1#Response: {
outcome: 'ACCEPTED'
}
} write "application/xml"
}
But I got this error:
The prefix myNs1 has not been previously declared using ns
I'm running on Mule 4.3.0
As aled have pointed out, it might have been a bug or incorrect information in the docs. From what I can see, the namespaces are properly imported but it seems that prefixes are expected to be declared locally.
You can use below:
%dw 2.0
import * from modules::Namespaces
output application/java
var myNs1Local = myNs1 as Namespace
---
{
body: {
myNs1Local#Response: {
outcome: 'ACCEPTED'
}
} write "application/xml"
}
which will result to the expected output.
{
body: "<?xml version='1.0' encoding='UTF-8'?>\n<myNs1:Response xmlns:myNs1=\"http://namespaces/my1\">\n <outcome>ACCEPTED</outcome>\n</myNs1:Response>" as String {class: "java.lang.String"}
} as Object {encoding: "UTF-8", mediaType: "*/*", mimeType: "*/*", class: "java.util.LinkedHashMap"}
Notice here that what I used as the prefix is the declared variable (myNs1Local) but it still write the prefix as referenced in Namespace.dwl

Setting Http response data as a varible in Mule4

I am trying to set http response values in variable. Below is response from http request
{
"kind": "drive#file",
"id": "1MxumGPQD9dH161BQJCoJ_",
"name": "2020_August",
"mimeType": "application/vnd.google-apps.folder"
}
How can i set only the id field in a variable after getting above reponse.
Am trying this logic in trans form message
%dw 2.0
output application/json
---
{
"id":payload.id
}
But giving me error
The content that's returned from your HttpRequest call is binary.
Try this:
%dw 2.0
output application/json
---
id: read(payload, "application/json").'id'
which should return what you're looking for:
{
"id": "1MxumGPQD9dH161BQJCoJ_"
}
If you are capturing that into a local variable, define the same using a set-variable, like this:
<set-variable value="#[read(payload, "application/json").'id']" doc:name="id" variableName="id"/>

Type mismatch for 'mapObject' operator in Mule 3.8.0 DataWeave that worked in 3.9.0

I built an API project that builds and sends a SOAP request to another service, based on parameters sent to the API. I inadvertently built the project in Mule 3.9.0 EE, when our production and dev Mule environments are 3.8.0 EE. The project works fine locally in 3.9.0, and it runs in 3.8.0 until it builds the request in Dataweave. It reports the following exception in 3.8.0:
Root Exception stack trace:
com.mulesoft.weave.engine.ast.dynamic.UnexpectedOperationTypesException: Type mismatch for 'mapObject' operator
found :array, :function
required :object, :function
I use two Dataweaves to build the request. The first builds the prompts used in the SOAP request from the parameters. The second builds the SOAP request and inserts the prompts.
The first Dataweave:
%dw 1.0
%output application/json
---
[flowVars.parameterMap mapObject (value, key)->{
PROMPT: {
PSQueryName: "",
UniquePromptName: key,
FieldValue: value
}
}]
The second Dataweave:
%dw 1.0
%output application/xml encoding="UTF-8"
%namespace SOAP-ENV http://schemas.xmlsoap.org/soap/envelope/
%namespace wsse http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd
%namespace qas http://xmlns.oracle.com/Enterprise/Tools/schemas/QAS_EXEQRY_SYNC_REQ_MSG.VERSION_1
%namespace qas1 http://xmlns.oracle.com/Enterprise/Tools/schemas/QAS_EXEQRY_SYNC_REQ.VERSION_1
---
{
SOAP-ENV#Envelope: {
SOAP-ENV#Header: {
wsse#Security #(SOAP-ENV#mustUnderstand: "1"): {
wsse#UsernameToken: {
wsse#Username: "someUsername",
wsse#Password #(Type: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"): "somePassword"
}
}
},
SOAP-ENV#Body: {
qas#QAS_EXEQRY_SYNC_REQ_MSG: {
qas1#QAS_EXEQRY_SYNC_REQ: {
QueryName: flowVars.queryName,
isConnectedQuery: "N",
OwnerType: flowVars.queryType,
BlockSizeKB: 0,
MaxRow: 0,
OutResultType: "webrowset",
OutResultFormat: "nonfile",
PROMPTS: payload.*PROMPT mapObject {
PROMPT: {
PSQueryName: $.PSQueryName when $.PSQueryName != "" otherwise {},
UniquePromptName: $.UniquePromptName,
FieldValue: $.FieldValue
}
}
}
}
}
}
}
In 3.9.0, the Dataweave transformed the SOAP request perfectly. In 3.8.0, it has issue with the PROMPTS: payload.*PROMPT mapObject statement in the second DataWeave.
What changed in 3.9.0 that made this work properly?
What work around can I do to resolve this issue in 3.8.0?
I solved this on my own by combining the two Dataweaves, which separating the two proved to be unnecessary.
It does not answer what changes occurred in 3.9.0 that allowed it to work in the original project.
%dw 1.0
%output application/xml encoding="UTF-8"
%namespace SOAP-ENV http://schemas.xmlsoap.org/soap/envelope/
%namespace wsse http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd
%namespace qas http://xmlns.oracle.com/Enterprise/Tools/schemas/QAS_EXEQRY_SYNC_REQ_MSG.VERSION_1
%namespace qas1 http://xmlns.oracle.com/Enterprise/Tools/schemas/QAS_EXEQRY_SYNC_REQ.VERSION_1
---
{
SOAP-ENV#Envelope: {
SOAP-ENV#Header: {
wsse#Security #(SOAP-ENV#mustUnderstand: "1"): {
wsse#UsernameToken: {
wsse#Username: "someUser",
wsse#Password #(Type: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"): "somePassword"
}
}
},
SOAP-ENV#Body: {
qas#QAS_EXEQRY_SYNC_REQ_MSG: {
qas1#QAS_EXEQRY_SYNC_REQ: {
QueryName: flowVars.queryName,
isConnectedQuery: "N",
OwnerType: flowVars.queryType,
BlockSizeKB: 0,
MaxRow: 0,
OutResultType: "webrowset",
OutResultFormat: "nonfile",
PROMPTS: flowVars.parameterMap mapObject (value, key)->{
PROMPT: {
PSQueryName: "",
UniquePromptName: key,
FieldValue: value
}
}
}
}
}
}
}

DataWeave - Transformer Mule error "There is no variable named 'message'"

How to display Outbound properties in mule via the DataWeave transformer?
I tried this:
%dw 1.0
%output application/json skipNullOn="everywhere"
---
{
test_property: message.outboundProperties.testProperty
}
but I get this error: There is no variable named 'message'.
Thanks.
invoke directly without using 'message' as shown below
test_property: outboundProperties.testProperty
or else define a flow variable and use it as below
flowvar1: flowVars.flowvar1

OSX - AFNetworking sending text even with JSON Serializer set

I have an issue with AFNetworking and AFJSONRequestSerializer. I try to access an API, and the request contains a text/plain header. Here's my code :
class BaseService {
var manager: AFHTTPRequestOperationManager!
init() {
manager = AFHTTPRequestOperationManager()
manager.responseSerializer = AFJSONResponseSerializer()
manager.requestSerializer = AFJSONRequestSerializer(writingOptions: NSJSONWritingOptions.allZeros)
}
}
class UserService: BaseService {
func startNewEntry(name: String) {
let params = [
"time_entry": [
"description": name,
"created_with": "fooBar"
]
]
manager.POST(
"endpoint",
parameters: params,
success: { (operation, response) -> Void in
let json = JSON(response)
println("OK")
println(json)
Context.shared.entries.getFromJSON(json)
}) { (operation, error) -> Void in
println("-- ERROR --")
println(operation)
println(error)
}
}
Do you know this issue ?
No, this code will create a request with a content type of application/json. But I wonder if you perhaps mislead by an error message that said:
Request failed: unacceptable content-type: text/html
If you got that, that's not telling you that that the request had an unacceptable content type, but rather that the request failed because the response was text/html. And this is a very common issue: If server code that is attempting to create a JSON response fails for some reason, sometimes the error message isn't JSON, but rather it's HTML.
I would suggest adding the following inside the failure block of your POST method in order to see what this text/html response was:
if operation.responseData != nil {
println(NSString(data: operation.responseData, encoding: NSUTF8StringEncoding))
}
This way, if you get a text error message from the server (e.g. the request was malformed or what have you), you'll be able to read the HTML response you got back.