Create a JSON Object based on input parameter in MuleSoft DataWeave 2.0 - mule

So I have a REST API which can have there input Params: START, STOP, RESTART. Start and Stop are distinct operations for the REST API but RESTART essentially means STOP and START. Hence I want to create a Dynamic JSON of either 1 node or 2 nodes based on the operation chosen For e.g. For START/STOP the JSON will be:
{ "appID": "1234",
"operation": "START"}
OR
{ "appID": "1234",
"operation": "STOP"}
While for RESTART it be be like:
{ "appID": "1234","operation": "STOP"},{ "appID": "1234","operation": "START"}
I can then loop through this array and call my API once or twice.However I am at a loss to understand how do I create this JSON dynamically in data weave based on the Operation param passed as an input to the REST API call.I have tried to create a variable with 2 node JSON nodes and then try too loop but that doesn't seem to be working.
I tried something like this:
var count = 0
var appID = "1234567890"
var op = "START"
---
(operation map ((item, index) -> {
"appID": appID,
"operation": if(op=='START' and index == 0) "START"
else if(op=='STOP' and index==0) "STOP"
else if(op=='RESTART' and index==0) "STOP"
else if(op=='RESTART' and index==1) "START"
else ''
})) [ 0 to operation.totalcount - count ]
where the value of Count is either 0 or 1 based on the operation

If I understand correctly if the input value operation is "RESTART" then the script should return an array of elements start and stop, if "START" just a start element and if "STOP" just a stop element. I assume the output is always an array.
For this script the variable op represents the input. I use the value of op to return the operation if it is not "RESTART". If it is I return "STOP" first and add a second element for "START".
%dw 2.0
output application/json
var appID = "1234567890"
var op = "RESTART"
---
[
{
"appID": appID,
"operation": if(op !='RESTART') op
else "STOP"
}
] ++ if (op =='RESTART') [{
"appID": appID,
"operation": "START"
}] else []
Output:
[
{
"appID": "1234567890",
"operation": "STOP"
},
{
"appID": "1234567890",
"operation": "START"
}
]

Related

Dataweave - how to accumulate json response from http request connector in for each component (Mule 4)

I consume a HTTP request and I need to save and accumulate the JSON response with out any transformation in a variable, I do that but I dont know why the accumulate it correctly, could you please tell me how can I solve that problem.
Json Response By Iteration:
Iteration 1:
{
"orderId": "11111",
"status": "false",
"receivedAt": "2022-07-28T22:45:12.175Z",
"createdAt": "2022-07-28T22:45:12.175Z",
}
Iteration 2:
{
"orderId": "22222",
"status": "false",
"receivedAt": "2022-07-28T22:45:27.907Z",
"createdAt": "2022-07-28T22:45:27.907Z"
}
Dataweave: (csv Payload is the name of the variable where the values accumulated)
%dw 2.0
output application/json
---
if ( vars.counter == 1)
( payload )
else
( vars.csvPayload ) ++ payload
Variable Result:
{
"orderId": "11111",
"status": "false",
"receivedAt": "2022-07-28T22:45:12.175Z",
"createdAt": "2022-07-28T22:45:12.175Z",
"orderId": "22222",
"status": "false",
"receivedAt": "2022-07-28T22:45:27.907Z",
"createdAt": "2022-07-28T22:45:27.907Z"
}
Variable Expected:
[
{
"orderId": "11111",
"status": "false",
"receivedAt": "2022-07-28T22:45:12.175Z",
"createdAt": "2022-07-28T22:45:12.175Z",
},
{"orderId": "22222",
"status": "false",
"receivedAt": "2022-07-28T22:45:27.907Z",
"createdAt": "2022-07-28T22:45:27.907Z"
}
]
NOTE: I don't know why the JSON responses of each iteration are joined in the same object and not as a different object in an array.
The incorrect output is easy. You are concatenating an object to another object. In that case the operator ++ "extracts all the key-values pairs from each object, then combines them together into one result object." according to the documentation. The parenthesis are totally unneeded.
Setting the output to JSON in each iteration -I'm assuming this is inside a foreach- is inefficient since it requires formatting the output to JSON in each iteration only to parse it again in the following one. I recommend to use application/java -which doesn't require parsing/formatting- inside a loop and after the loop convert the entire output to JSON in one go.
You should use an array to hold the values, so assign an empty array ([]) to the variable before the foreach loop to initialize it. Then the counter is unneeded since you can just add elements to the array:
%dw 2.0
output application/java
---
vars.allOrders ++ payload
Then after the foreach just transform the array to JSON:
%dw 2.0
output application/json
---
vars.allOrders
Your requirement is a very common scenario in integrations.
Assuming you are using HTTP Requester inside a for-each loop and initialized the variable to hold the final Payload (lets say var finalPayload = []) before the loop, you have to keep on updating the same variable (append the new data in the same array variable like below) with the response payload received from HTTP Requester for each iteration.
var finalPayload << payload
Ultimately check the finalPayload outside for-each loop, that will give you your desired result.

Handling multiple rows returned by IMPORTJSON script on GoogleSheets

I am trying to populate a google sheet using an API. But the API has more than one row to be returned for a single query. Following is the JSON returned by API.
# https://api.dictionaryapi.dev/api/v2/entries/en/ABANDON
[
{
"word": "abandon",
"phonetics": [
{
"text": "/əˈbændən/",
"audio": "https://lex-audio.useremarkable.com/mp3/abandon_us_1.mp3"
}
],
"meanings": [
{
"partOfSpeech": "transitive verb",
"definitions": [
{
"definition": "Cease to support or look after (someone); desert.",
"example": "her natural mother had abandoned her at an early age",
"synonyms": [
"desert",
"leave",
"leave high and dry",
"turn one's back on",
"cast aside",
"break with",
"break up with"
]
},
{
"definition": "Give up completely (a course of action, a practice, or a way of thinking)",
"example": "he had clearly abandoned all pretense of trying to succeed",
"synonyms": [
"renounce",
"relinquish",
"dispense with",
"forswear",
"disclaim",
"disown",
"disavow",
"discard",
"wash one's hands of"
]
},
{
"definition": "Allow oneself to indulge in (a desire or impulse)",
"example": "they abandoned themselves to despair",
"synonyms": [
"indulge in",
"give way to",
"give oneself up to",
"yield to",
"lose oneself in",
"lose oneself to"
]
}
]
},
{
"partOfSpeech": "noun",
"definitions": [
{
"definition": "Complete lack of inhibition or restraint.",
"example": "she sings and sways with total abandon",
"synonyms": [
"uninhibitedness",
"recklessness",
"lack of restraint",
"lack of inhibition",
"unruliness",
"wildness",
"impulsiveness",
"impetuosity",
"immoderation",
"wantonness"
]
}
]
}
]
}
]
By using the following calls via IMPORTJSON,
=ImportJSON(CONCATENATE("https://api.dictionaryapi.dev/api/v2/entries/en/"&$A2), "/phonetics/text", "noHeaders")
=ImportJSON(CONCATENATE("https://api.dictionaryapi.dev/api/v2/entries/en/"&$A2), "/meanings/partOfSpeech", "noHeaders")
=ImportJSON(CONCATENATE("https://api.dictionaryapi.dev/api/v2/entries/en/"&$A2), "/meanings/definitions/definition", "noHeaders")
=ImportJSON(CONCATENATE("https://api.dictionaryapi.dev/api/v2/entries/en/"&$A2), "/meanings/definitions/synonyms", "noHeaders")
=ImportJSON(CONCATENATE("https://api.dictionaryapi.dev/api/v2/entries/en/"&$A2), "/meanings/definitions/example", "noHeaders")
I am able to get the following in GoogleSheets,
Whereas, the actual output according to JSON should be,
As you can see a complete row is being overwritten. How can this be fixed?
EDIT
Following is the link to sheet for viewing only.
I believe your goal as follows.
You want to achieve the bottom image in your question on Google Spreadsheet.
Unfortunately, I couldn't find the method for directly retrieving the bottom image using ImportJson. So in this answer, I would like to propose a sample script for retrieving the values you expect using Google Apps Script. I thought that creating a sample script for directly achieving your goal might be simpler rather than modifying ImportJson.
Sample script:
function SAMPLE(url) {
var res = UrlFetchApp.fetch(url, {muteHttpExceptions: true});
if (res.getResponseCode() != 200) return res.getContentText();
var obj = JSON.parse(res.getContentText());
var values = obj[0].meanings.reduce((ar, {partOfSpeech, definitions}, i) => {
definitions.forEach(({definition, example, synonyms}, j) => {
var v = [definition, Array.isArray(synonyms) ? synonyms.join(",") : synonyms, example];
var phonetics = obj[0].phonetics[i];
ar.push(j == 0 ? [(phonetics ? phonetics.text : ""), partOfSpeech, ...v] : ["", "", ...v]);
});
return ar;
}, []);
return values;
}
When you use this script, please put =SAMPLE(CONCATENATE("https://api.dictionaryapi.dev/api/v2/entries/en/"&$A2)) to a cell as the custom formula.
Result:
When above script is used, the following
Note:
In this sample script, when the structure of the JSON object is changed, it might not be able to be used. So please be careful this.
References:
Class UrlFetchApp
Custom Functions in Google Sheets

Postman JSON value check test fails

I have an API which has response as below:
"data": {
"catalog_list_items": [
{
"catalog_list_items": [
{
"catalog_list_items": [
{
"title": "L13",
"content_id": "58a85146b0000ec",
"sequence_no": 1,
"language": "hindi",
"genres": [
"xxxx"
]
I would like to create a test in postman to verify that the language key has value as 'hindi'. I am writing below test in Postman which always fails. Cannot find the reason.
var jsonData = JSON.parse(responseBody);
tests["Language is hindi"] = jsonData.data.catalog_list_items[3].language === "hindi";
However, when I use the similar structure to test sequence_no, it works fine
var jsonData = JSON.parse(responseBody);
tests["Sequence No is 1"]= jsonData.data.catalog_list_items[3].sequence_no === 1;
Can anyone shed a light for me?
I could see 3 level nested arrays in your response body.
So I don't know how are you getting your value through this expression:
jsonData.data.catalog_list_items[3].language
The correct expression to get the 'language' key from above response should be:
jsonData.data.catalog_list_items[0].catalog_list_items[0].catalog_list_items[0].language

How to get unnamed object instead of an array in case of only one result in Dataweave

We have a transformation with Dataweave which processes a list of objects. We get a json response like that:
{"hotels": [{
"name": "Hotel Oslo",
"propertyCode": "12345",
"currency": "NOK"
},
{
"name": "Hotel Stockholm",
"propertyCode": "12346",
"currency": "SEK"
}]}
However, in the case of only 1 response, we want to have the following response:
{"name": "Hotel Stockholm",
"propertyCode": "12346",
"currency": "SEK"}
We are generating the response like this:
{
hotels: payload.rows map ((row , indexOfRow) -> {
name: row.content.companyName.content,
propertyCode: row.content.propertyCode.content,
currency: row.content.currencyCode.content
})}
What should we put as a condition so that we do not get an array in case of 1 result?
Try this:
%dw 1.0
%output application/json
%function makeHotel(row) {
name: row.name,
propertyCode: row.propertyCode,
currency: row.currency
}
---
{
hotels: payload.rows map ((row , indexOfRow) -> makeHotel(row))
} when ((sizeOf payload.rows) != 1)
otherwise makeHotel(payload.rows[0])
It will give you an empty array on empty input, the simple object for one input and the structure with array when you have more than one input row.
(For test purposes, with a slightly differnt input structure, but the general solution should be clear.)

Subcribe a channel / real-time notification

Question about real-time notification..
Post: https://xxxiot.cumulocity.com/cep/realtime
Body:
[
{
"channel": "/meta/handshake",
"version": "1.0",
"mininumVersion": "1.0beta",
"supportedConnectionTypes": ["long-polling","callback-polling"],
"advice":{"timeout":120000,"interval":30000}
}
]
My Response:
[
{
"minimumVersion": "1.0",
"supportedConnectionTypes": [
"smartrest-long-polling",
"long-polling"
],
"successful": true,
"channel": "/meta/handshake",
"ext": {
"ack": true
},
"clientId": "5o0ghvle7yy4ix41on423v6k3j87",
"version": "1.0"
}
]
After received the clientId.. I have run the following command:
Post: https://xxxiot.cumulocity.com/cep/realtime
Body:
[
{
"channel": "/meta/subscribe",
"clientId": "5o0ghvle7yy4ix41on423v6k3j87",
"subscription": "/alarms/overHeatAlarms"
}
]
Response:
[
{
"error": "403:denied_by_security_policy:create_denied",
"subscription": "/alarms/overHeatAlarms",
"successful": false,
"channel": "/meta/subscribe"
}
]
Where is the problem? I'm trying to subcribing to "overheatAlarms"!
It may be that it does not exist? Can I read the existing information?
Thanks,
Alim
Yes, your suspicion is correct. There are basically two options for you:
Subscribe to all alarms or alarms from a particular device: Use "/cep/realtime" and channel "/alarms/* resp. channel "/alarms/[device ID]".
Create a processing rule that filters out overheat alarms and subscribe to that rule: Use "/cep/notifications" and channel "/[module name]/[statement name]".
The module name is what you enter as name when you click "New module". The statement name is what you add to the statement, e.g.
#Name('overHeatAlarms')
select * from AlarmsCreated where [your condition for overheat alarms]
(If you don't put a name there, they will be name statement_1, statement_2, ....)
To get notifications from Java, have a look at an example of getting notifications for changes in devices. In the subscribe() method, you pass "*" or the device ID. To get the notification, pass an implementation of SubscriptionListener, in particular the onNotification method. You can modify "channelPrefix" to "/alarms/" or "/measurements/" to get other notifications.
Thanks, André.
I've tested following Code Snippet.. it works, but it is not the best solution :-)
MeasurementApi measurementApi = getMeasurementApi();
MeasurementFilter measurementFilter = new MeasurementFilter();
while (true) {
Calendar cal = Calendar.getInstance();
Date toDate = cal.getTime();
cal.add(Calendar.SECOND, -25);
Date fromDate = cal.getTime();
measurementFilter.byDate(fromDate, toDate);
measurementFilter.byFragmentType(TemperatureMeasurement.class);
measurementFilter.bySource(new GId(DEVICE_SIMULATOR));
MeasurementCollection mc = measurementApi
.getMeasurementsByFilter(measurementFilter);
MeasurementCollectionRepresentation measurements = mc.get();
for (; measurements != null; measurements = mc
.getNextPage(measurements)) {
for (MeasurementRepresentation measurement : measurements
.getMeasurements()) {
TemperatureMeasurement temperatureSensor = measurement
.get(TemperatureMeasurement.class);
System.out.println(measurement.getSource().getId() + " "
+ measurement.getTime()+ " " + temperatureSensor.getTemperature() );
}
}
}