I have this json payload, I would want to collect all externalListingId in one shot -
{
"listings": {
"numFound": 3,
"listing": [
{
"status": "INACTIVE",
"pricePerTicket": {
"amount": 100,
"currency": "USD",
},
"paymentType": "1",
"externalListingId": "12208278",
"city": "New York"
},
{ "status": "ACTIVE",
"pricePerTicket": {
"amount": 4444,
"currency": "USD"
},
"paymentType": "1",
"externalListingId": "CID1421798897102:151681733",
"city": "Seattle"
}
]
}
}
I am using MVEL expression -
<enricher target="#[flowVars['sData']]" source="#[(externalListingId in payload.listing)]" doc:name="Message Enricher">
<json:json-to-object-transformer returnClass="java.util.HashMap" doc:name="JSON to Object"/>
</enricher>
But this is giving error !! - Message payload is of type: ReleasingInputStream.
Scenario - I would like to collect all externalListingId into flowVariable, convert to hashmap. I have another CSV file as input, would like to loop through that payload and check if this map contains the id!!
I am following this earlier post -
Extracting array from JSON in mule esb
You need to transform the message's streaming payload to an object with:
<json:json-to-object-transformer returnClass="java.lang.Object" />
before the enricher, and remove the one you have inside of it.
You also need to fix your MEL, as the listings property is missing in it:
source="#[(externalListingId in payload.listings.listing)]"
Source: http://www.mulesoft.org/documentation/display/current/Mule+Expression+Language+Tips#MuleExpressionLanguageTips-JSONProcessing
it worked with the same definition.
<flow name="test-mule-json-extractFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/json" doc:name="HTTP"/>
<enricher source="#[(externalListingId in payload.listings.listing)]" target="#[flowVars.ids]" doc:name="Message Enricher">
<json:json-to-object-transformer returnClass="java.util.HashMap" doc:name="JSON to Object"/>
</enricher>
<logger message=":::::::::::::::#[flowVars.ids]" level="INFO" doc:name="Logger"/>
</flow>
Note: the json input you mentioned is not valid due to available of an extra comma.
Related
I am making use of XSLT mediator to form the following JSON payload:
{
"products": [
{
"product_id": 1,
"product_name" : "abc"
},
{
"product_id": 2,
"product_name" : "xyz"
}
]
}
Based on the response I get from the api using the above payload, I need to create another json payload(below) and append it to make another api call.
{
"amount": {
"total_amount": 0.46,
"total_tax": 0
}
}
I want the final payload to look like
{
"products": [
{
"product_id": 1,
"product_name" : "abc"
},
{
"product_id": 2,
"product_name" : "xyz"
}
],
"amount": {
"total_amount": 0.46,
"total_tax": 0
}
}
How can I achieve this on WSO2 Integration studio?
I think XSLT is an overkill for this and I don't think Datamapper is a viable option here, given we are dealing with multiple inputs. You can simply use the Enrich Mediator for this. Here is an example for your payloads. I tried to provide an example as close to your requirement, I have hardcoded the payloads, and the Payload Factory depicts your backend call response and the original PL.
<?xml version="1.0" encoding="UTF-8"?>
<api context="/json" name="TestAPI" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="GET">
<inSequence>
<payloadFactory description="Build JSON" media-type="json">
<format>
{
"products": [
{
"product_id": 1,
"product_name" : "abc"
},
{
"product_id": 2,
"product_name" : "xyz"
}
]
}
</format>
<args/>
</payloadFactory>
<enrich description="First save the Original PL to a property" >
<source clone="true" type="body"/>
<target property="ORIGINAL_PL" type="property"/>
</enrich>
<payloadFactory description="Build JSON second PL" media-type="json">
<format>
{
"amount": {
"total_amount": 0.46,
"total_tax": 0
}
}
</format>
<args/>
</payloadFactory>
<enrich description="Save the PL from the second request to another property">
<source clone="true" type="body"/>
<target property="SECOND_PL" type="property"/>
</enrich>
<enrich description="Restore original payload">
<source clone="false" property="ORIGINAL_PL" type="property"/>
<target type="body"/>
</enrich>
<enrich description="Now add the second PL as a Child to the original" >
<source clone="true" property="SECOND_PL" type="property"/>
<target action="child" xpath="json-eval($)"/>
</enrich>
<log level="full"/>
<respond/>
</inSequence>
<outSequence/>
<faultSequence/>
</resource>
</api>
This is the result of the above.
{
"products": [
{
"product_id": 1,
"product_name": "abc"
},
{
"product_id": 2,
"product_name": "xyz"
}
],
"amount": {
"total_amount": 0.46,
"total_tax": 0
}
}
You can use DataMapper mediator to provide input and output schema and transform the incoming payload to the way you need. Provide either JSON or XML schema that you are receiving from the 1st service as the input schema to DataMapper and provide the schema of the expected result in either JSON or XML to the DataMatter as output schema. After that, you can map both input/ output fields and at runtime, DataMapper will do the message translation for you.
For more details - https://apim.docs.wso2.com/en/latest/tutorials/integration-tutorials/transforming-message-content/
Thanks!
I have the below json output:
{
"results": [
{
"ID": "1",
"ImageID": "2",
"Name": "Test1",
"Owner": "sysadmin",
"Author": "sysadmin",
"Creator": "sysadmin"
},
{
"ID": "2",
"ImageID": "23",
"Name": "Test2",
"Owner": "sysadmin",
"Author": "sysadmin",
"Creator": "sysadmin"
}
]
}
For each ID in above response, i need to invoke the rest service passing ID as a parameter and the rest service will send me a response back. I have to consolidate all the output into a single json response in mule.
I have tried using for each and enricher but could not able to build it. Below is the code which i am using.
<foreach doc:name="For Each Loop">
<logger level="INFO" message="#[payload]" doc:name="Logger" category="INFO"/>
<json:json-to-object-transformer doc:name="JSON to Object"/>
<enricher doc:name="Message Enricher">
<http:request config-ref="SAM" path="/abc/#[payload.ID]" method="GET" doc:name="HTTP"/>
<enrich target="#[flowVars.ID]" source="#[payload[0].ID]"/>
</enricher>
<logger level="INFO" message="#[flowVars.ID]" doc:name="Logger" />
<expression-component doc:name="Expression"><![CDATA[payload.ID = flowVars.ID; ]]></expression-component>
</foreach>
Kindly help me with the way to fix this !!
Thanks
You need to initialize an empty array before the for-each loop and add to that array within the for-each:
<set-variable variableName="idList" value="#[[]]" doc:name="Variable - Init idList"/>
<foreach doc:name="For Each Loop">
<logger level="INFO" message="#[payload]" doc:name="Logger" category="INFO"/>
<json:json-to-object-transformer doc:name="JSON to Object"/>
<enricher doc:name="Message Enricher">
<http:request config-ref="SAM" path="/abc/#[payload.ID]" method="GET" doc:name="HTTP"/>
<enrich target="#[flowVars.ID]" source="#[payload[0].ID]"/>
</enricher>
<logger level="INFO" message="#[flowVars.ID]" doc:name="Logger" />
<expression-component doc:name="Expression"><![CDATA[flowVars.idList.add(flowVars.ID);]]></expression-component>
</foreach>
I cover this topic in this video.
Thanks Jerney !!
I made it working by doing the following:
<set-variable variableName="outputList" value="#[new java.util.ArrayList()]" doc:name="SetEmptyArray"/>
<foreach collection="json:packshots" doc:name="ForEachDocument">
<set-variable variableName="docName" value="#[json:Name]" doc:name="docName"/>
<http:request config-ref="AH_DAM_API_Configuration" path="${ah.dam.api.get.renditions.path}#[json:Name]" method="GET" doc:name="InvokeAHDamService"/>
<set-payload value="#[xpath3('//*:service/*:document',payload,'NODE')]" doc:name="fetchRenditionInfo"/>
<expression-transformer expression="#[flowVars.outputList.add(payload)]" doc:name="AppendResponseToArray"/>
</foreach>
I have used from the savedOutput for array variable.
The mule payload is in flowVars (infodata)
[
{
"status": "submitted",
"identity": "",
"papers": {
"code1": "12csd3cbsdj",
"code2": "skd02nd28dn",
"date": "2016-06-22",
"party": {
"due_date": "2016-06-22",
"personel": {
"email": "tt#test.com",
"value": {
"amount": "0.10",
"inflation": "HIGH"
}
}
}
}
}
]
Inside Dataweave,
(1) how to remove the square brackets?
(2) how to replace the value of amount and inflation dynamically (from flowVars)?
Question 2:You can directly use flowVars inside dataweave or if the values are in url you can dynamically set values using inboundProperties. Refer: https://docs.mulesoft.com/mule-user-guide/v/3.7/dataweave-reference-documentation
I have used set variable where you can dynamically exact it.Test Url used in this flow: http://localhost:8083/test?inflation=HIGH
<flow name="testFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/" doc:name="HTTP">
</http:listener>
<logger level="INFO" doc:name="Logger"/>
<set-variable variableName="dynamicValueAmount" value="#['2']" doc:name="Variable"/>
<dw:transform-message doc:name="Transform Message">
<dw:set-payload><![CDATA[%dw 1.0
%output application/json
---
[
{
"status": "submitted",
"identity": "",
"papers": {
"party": {
"due_date": "2016-06-22",
"personel": {
"email": "tt#test.com",
"value": {
"amount": flowVars.dynamicValueAmount,
"inflation": inboundProperties.'http.query.params'.inflation
}}}}}
]]]></dw:set-payload>
</dw:transform-message>
<object-to-string-transformer doc:name="Object to String"/>
<set-payload value="#[ message.payload =org.mule.util.StringUtils.replace(message.payload,"[","{");message.payload =org.mule.util.StringUtils.replace(message.payload,"]","}")]" doc:name="Set Payload"/>
<logger level="INFO" doc:name="Logger"/>
</flow>
Regarding Question one, i have externally used replace function in set Payload( Working fine - other way). I believe it can be achieve in standard way by using Dataweave itself. Let wait for the answers.
I have resolved question #1
%dw 1.0
%output application/java
---
{
data:flowVars.infodata replace /(\[|\])/ with ""
}
I'm still trying to understand how to dynamically change the content of the payload for question #2.
Looking at the sample flowVar content, it looks like an array of json object. Is that correct? If it is array then inside dataweave, you can either iterate over flowVars.infodata map {} or just get the first object data: flowVars.infodata[0].
Not sure what you really mean by dynamically changing content. #star has shown a way how you can reference any variables inside your dataweave code. May be you can add some of your code that you are looking to edit?
I've a JSON response that I'd like to iterate through and capture the values of incident
number, the longtitude, latitude as a group and send it to an SMS messaging service. I've tried
different approaches but I'm not able to get to these elements. I've tried to debug and use
different expressions without any luck. Suggestions are appreciated.
[
{
"type": " --T::00"
},
{
"address": "2720 E Madison St",
"longitude": "-122.296667",
"latitude": "47.623153",
"incident_number": "F110104004",
"type": "Medic Response",
"report_location": {
"needs_recoding": false,
"longitude": "-122.296667",
"latitude": "47.623153"
}
},
{
"address": "2260 1st Av S",
"longitude": "-122.334199",
"latitude": "47.583347",
"incident_number": "F110103709",
"type": "Aid Response",
"report_location": {
"needs_recoding": false,
"longitude": "-122.334199",
"latitude": "47.583347"
}
},
{
"address": "1930 Boren Av",
"longitude": "-122.333103",
"latitude": "47.617173",
"incident_number": "F110103707",
"type": "Aid Response",
"report_location": {
"needs_recoding": false,
"longitude": "-122.333103",
"latitude": "47.617173"
}
]
Here's the configuration file.
<flow name="seattleemergencyFlow1" doc:name="seattleemergencyFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8900" path="get-emergency" doc:name="HTTP"/>
<http:outbound-endpoint exchange-pattern="request-response" host="data.seattle.gov" port="80" path="resource/kzjm-xkqj.json?" method="GET" contentType="application/json" doc:name="HTTP"/>
<json:json-to-object-transformer doc:name="JSON to Object" returnClass="java.util.List"/>
</flow>
After converting the json to a List<Object> using the json:json-to-object-transformer as you have. You should be able to just use any of Mule's collection features such as the foreach scope/router and then MEL expressions to access specific fields:
<foreach>
<logger level="ERROR" message="#[payload.address]" />
</foreach>
you also convert json to xml data using
<json:json-to-xml-transformer doc:name="json-to-xml"/>
transformer and provide the xpath expression on for-each scope as below
<foreach collection="#[xpath('---')]" batchSize="--" doc:name="for-each-account-batch">
I have a REST service in my Mule flow :-
<flow name="restServiceFlow1" doc:name="restFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8082" doc:name="HTTP"/>
<jersey:resources doc:name="REST">
<component class="com.test.services.schema.maindata.v1.Impl.MainDataImpl"/>
</jersey:resources>
</flow>
and I have another flow which sends JSON request from a file to that service flow and consume it :-
<flow name="restFlow2" doc:name="restFlow2">
<file:inbound-endpoint path="E:\backup\test" responseTimeout="10000" doc:name="File" connector-ref="File_Global">
<file:filename-regex-filter pattern="aa.txt" caseSensitive="false"/>
</file:inbound-endpoint>
<json:json-to-object-transformer returnClass="java.util.HashMap" doc:name="JSON to Object"/>
<http:outbound-endpoint exchange-pattern="request-response" contentType="application/json" method="GET" address="http://localhost:8082/getData/insert/?id=#[payload.insertDataRequest[0].id]&name=#[payload.insertDataRequest[0].name]&age=#[payload.insertDataRequest[0].age]&designation=#[payload.insertDataRequest[0].designation]" doc:name="HTTP"/>
</flow>
Now my JSON request is :-
{
"insertDataRequest": [
{
"id": "6",
"name": "ddddd",
"age": "55",
"designation": "WQQQQQ"
},
{
"id": "64",
"name": "mmmm",
"age": "545",
"designation": "TTTTTTTTTT"
}
]
}
Now, the issue is whenever I place the JSON request as a file ... only the first Data is inserted .. that is only
{
"id": "6",
"name": "ddddd",
"age": "55",
"designation": "WQQQQQ"
}
is getting inserted in DB ..
.... .... Now I want all the Data to be inserted in Database ... How can I achieve it ?? ..Do I need any for each to get all the Data ??... Please Help...
Use a for each block to iterate on the insertDataRequest entries:
<flow name="restFlow2">
<file:inbound-endpoint path="E:\backup\test" responseTimeout="10000" connector-ref="File_Global">
<file:filename-regex-filter pattern="aa.txt" caseSensitive="false"/>
</file:inbound-endpoint>
<json:json-to-object-transformer returnClass="java.util.HashMap"/>
<foreach collection="#[payload.insertDataRequest]">
<http:outbound-endpoint exchange-pattern="request-response"
contentType="application/json" method="GET"
address="http://localhost:8082/getData/insert/?id=#[payload.id]&name=#[payload.name]&age=#[payload.age]&designation=#[payload.designation]"/>
</foreach>
</flow>
Note that the fact you're performing insertions with GET instead of a POST is not respectful of the REST principles...