Iterate Mediator over json arrays - json

I'd like to iterate the results array of a json message
{
"results":[
{
"category":"mdl",
"subcategory":"ip",
"ip":"103.14.120.121",
"subtype":"IP-MDL",
"date":"1405074556",
"longitude":"75.3333",
"latitude":"19.8833",
"country":"India",
"city":"Aurangabad",
"organization":"Good Domain Registry Private Limited",
"isp":"Good Domain Registry Private Limited"
},
{
"category":"mdl",
"subcategory":"ip",
"ip":"108.162.198.96",
"subtype":"IP-MDL",
"date":"1405074556",
"longitude":"-122.3933",
"latitude":"37.7697",
"country":"United States",
"city":"San Francisco",
"organization":"CloudFlare",
"isp":"CloudFlare"
}
]
}
unfortunately iteration mediator doesn't seem to accept non xpath expression
anyone knows how to iterate over the previous message json results the same way i do it in xml ?
I'd like to use ESB json-native support but doesn't seem to be able to break down json messages as with XML (i've tried iterate mediator, json payload factory and script mediator without any success)
<iterate expression="json-eval(results)">
<target>
<sequence>
<property name="messageType" value="application/json" scope="axis2"/>
<payloadFactory media-type="json">
<format>
{
"event":{
"providerName":"$1",
"providerSource":"$2",
"providerClassification":"$3",
"providerVersion":"$4",
"body":{
"results":{$5}
}
}
}
</format>
<args>
<arg value="bdigital"/>
<arg evaluator="json" expression="$.results.category"/>
<arg evaluator="json" expression="$.results.subcategory"/>
<arg value="1.0"/>
<arg evaluator="json" expression="$.results"/>
</args>
</payloadFactory>
<call>
<endpoint>
<http method="post"
uri-template="http://BD-VM-PP-CIC01:8280/services/CICQueue"/>
</endpoint>
</call>
</sequence>
</target>
</iterate>
thanks in advance,

You could do the following?
<property name="messageType" value="application/xml" scope="axis2" type="STRING"></property>
<iterate xmlns:ns="http://org.apache.synapse/xsd" continueParent="true" expression="//jsonObject/results" id="MyIterator">
<target>
<sequence>
<property name="cat" expression="json-eval($.results.category)" type="STRING"></property>
etc.

There is a new version in WSO2 EI in which you can iterate over JSON using JSON Path. You can do something like below.
<iterate id="iterate-over-users" preservePayload="true" attachPath="json-eval($.results)" expression="json-eval($.results)">
<target>
<sequence>
<send>
<endpoint>
<http method="POST" uri-template="http://backend.com"/>
</endpoint>
</send>
</sequence>
</target>
</iterate>
Refer to the following blog for more info. https://medium.com/#arunans23/iterate-over-json-payload-with-wso2-enterprise-integrator-8ccb9cdd2c70

Related

Dynamically add new element to json payload in WSO2 EI by using enrich mediator

I need to enrich existing json payload with new elements which is dynamically passed to existing payload instead of static value. Can anyone please help me?
Existing payload:
{
"Type":"CAR",
"Identifier":"2db23c39-9d3f-4e61-b3c5-e8725a2f1b90",
"ListingType":"New",
"SaleStatus":"For Sale"
}
Expected :
{
"Type":"CAR",
"Identifier":"2db23c39-9d3f-4e61-b3c5-e8725a2f1b90",
"ListingType":"New",
"SaleStatus":"For Sale",
"messageId":"urn:uuid:ccdafb72-c4"
}
Here messageId is ESB generated MessageID automatically.
<!-- ************API Request set to incomingRequest property************ -->
<property description="incomingRequest" expression="json-eval($.)" name="incomingRequest"
scope="default" type="STRING"/>
<payloadFactory media-type="json">
<format>$1</format>
<args>
<arg evaluator="xml" expression="get-property('incomingRequest')"/>
</args>
</payloadFactory>
<enrich description="">
<source type="inline" clone="true">
<messageId xmlns="">evaluate(get-property('operation','messageId'))
</messageId>
</source>
<target action="child" xpath="//jsonObject" />
</enrich>
<enrich>
<source clone="true" xpath="//jsonObject" />
<target type="body" />
</enrich>
<log level="full"/>
**Getting Wrong output**
{
"Type":"CAR",
"Identifier":"2db23c39-9d3f-4e61-b3c5-e8725a2f1b90",
"ListingType":"New",
"SaleStatus":"For Sale",
"messageId": "evaluate(get-property('operation','messageId'))"
}
Note:
I have followed this
Inline content on the enrich mediator is not evaluated. (considered as string)
So, we can use the property mediator to evaluate the expression.
<property name="prop1" expression="get-property('operation','messageId')"/>
Then we can use the above property in enrich mediator.
<enrich description="">
<source type="property" property="prop1"></source>
<target action="child" xpath="//jsonObject" />
</enrich>
BTW, In latest product versions, the Enrich mediator has the native JSON support.
More details in Here
I had similar scenario where i wanted to append some elements to a received json response:
First i got the response received into a property:
property expression="json-eval($)" name="RESPONSE" scope="default"
type="STRING"
Then i created a payload and added the new properties:
<payloadFactory media-type="json">
<format>
{"details": $1,
"timestamp":"$2",
"value":"$3"}
</format>
<args>
<arg evaluator="xml"
expression="get-property('RESPONSE')" />
<arg evaluator="xml"
expression="get-property('REQUEST_TIMESTAMP')" />
<arg evaluator="xml"
expression="get-property('VALUE')" />
</args>
</payloadFactory>
Then I returned the response using loopback. Note that REQUEST_TIMESTAMP and VALUE are defined as properties.

WSO2 API Manager Tool: Unable to convert JSONtoSOAP and then SOAPtoJSON to communicate between mock backend and API

Following the guidelines from WSO2 Documentation at: https://docs.wso2.com/display/AM260/Convert+a+JSON+Message+to+SOAP+and+SOAP+to+JSON
The intended response was
I revised it a couple times but keep getting "400: bad request error"
my curl and the error
EDIT¹: After running tests I found out that the issue is just with the SOAPtoJSON conversion. When I POST without the OUT (SOAPtoJSON) sequence, I get the XML answer exactly as intended as shown here
Thats my JSONtoSOAP.xml:
<?xml version="1.0" encoding="UTF-8"?>
<sequence name="JSONtoSOAP" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
<payloadFactory media-type="xml">
<format>
<soap12:Envelope xmlns:soap12="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap12:Body>
<CheckPhoneNumber xmlns="http://ws.cdyne.com/PhoneVerify/query">
<PhoneNumber>$1</PhoneNumber>
<LicenseKey>$2</LicenseKey>
</CheckPhoneNumber>
</soap12:Body>
</soap12:Envelope>
</format>
<args>
<arg evaluator="xml" expression="//request/PhoneNumber" literal="true"/>
<arg evaluator="xml" expression="//request/LicenseKey" literal="true"/>
</args>
</payloadFactory>
<property name="messageType" scope="axis2" type="STRING" value="application/soap+xml"/>
</sequence>
Thats my SOAPtoJSON.xml:
<?xml version="1.0" encoding="UTF-8"?>
<sequence name="SOAPtoJSON" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
<log level="custom" separator=",">
<property name="TRACE" value="Global Mediation Extension"/>
</log>
<payloadFactory media-type="xml">
<format>
<CheckPhoneNumber xmlns="http://ws.cdyne.com/PhoneVerify/query">
<PhoneNumber>$1</PhoneNumber>
<LicenseKey>$2</LicenseKey>
</CheckPhoneNumber>
</format>
<args>
<arg evaluator="xml" expression="//request/PhoneNumber"/>
<arg evaluator="xml" expression="//request/LicenseKey"/>
</args>
</payloadFactory>
<property name="messageType" scope="axis2" type="STRING" value="application/json"/>
</sequence>
I'm really new to the technology. And I just followed the steps from the documentation as mentioned. Maybe is was just a silly mistake (even though I revised it several times)
Maybe someone got the same problem and can help me out.
Thanks in advance.
Here is a new feature which generates a REST interface for your SOAP service. Try that. It supports SOAP-REST conversion automatically.
https://docs.wso2.com/display/AM260/Generate+REST+APIs+from+SOAP+Backends

How can I create a JSON payload with text containing XML in it?

I try to create an automatic JIRA problem reporting (in some FAULT sequences.
I make a JSON payload for JIRA APIs what works just fine for text.
I would like to however report to JIRA a SOAP request and response whereby I could investigate on the issue.
my question is how can I create a JSON payload with text containing XML in it?
I get this exception in WSO2 ESB
[2016-09-18 21:46:31,774] ERROR - NativeWorkerPool Uncaught exception
java.lang.Error: Error: could not match input
at org.apache.synapse.commons.staxon.core.json.stream.impl.JsonScanner.zzScanError(JsonScanner.java:530)
at org.apache.synapse.commons.staxon.core.json.stream.impl.JsonScanner.yylex(JsonScanner.java:941)
payload which I want to generate
<payloadFactory description="" media-type="json">
<format>
{
"fields": {
"project":
{
"key": "$1"
},
"summary": "$2",
"description": "$3",
"issuetype": { "name": "$4" }
}
}
</format>
<args>
<arg evaluator="xml" expression="$func:projectKey"/>
<arg evaluator="xml" expression="$func:summary"/>
<arg evaluator="xml" expression="$func:description"/>
<arg evaluator="xml" expression="$func:issueType"/>
</args>
</payloadFactory>
and I want to send some text containing XML into the parameter $func:description. When I sent only poor XML into the $func:description, the payload Factory transferred into into JSON what is not needed in this case, the the XML is supposed to be a text - the message
for the completeness to get the XML message I used
<property expression="$body" name="request"
scope="default" type="STRING"/>
call the end-point
<property expression="$body" name="response"
scope="default" type="STRING"/>
and I need to know bind "request" + "response" into $func:description
If the XML is well-formed you can simply set messageType property to application/json and do the conversion automatically. Refer this for more details.
Or else you can use the payload Factory mediator or Enrich mediator to custom build your Json.
create the payload with the XML structure you like.
use JS script mediator to modify one node as CDATA.
change the content type.
My proxy config, please do the change you need for your requirement:
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="XMLinsideJSON"
transports="http https"
startOnLoad="true">
<target>
<inSequence>
<property name="BOK" expression="//*[1]" type="OM" scope="default"/>
<enrich>
<source type="inline" clone="true">
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<fields xmlns="">
<summary xmlns=""/>
<project xmlns=""/>
<description xmlns=""/>
<issuetype xmlns="">
<name xmlns=""/>
</issuetype>
</fields>
</soapenv:Body>
</soapenv:Envelope>
</source>
<target type="envelope"/>
</enrich>
<script language="js">
importPackage(Packages.org.apache.axiom.om);
var elem= mc.getEnvelope().getBody().getFirstElement().getFirstElement();
var myText = elem.getOMFactory().createOMText(elem, mc.getProperty("BOK"), OMNode.CDATA_SECTION_NODE);
elem.addChild(myText)
</script>
<property name="messageType" scope="axis2" value="application/json"/>
<respond/>
</inSequence>
<outSequence>
<send/>
</outSequence>
</target>
</proxy>
My request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<payload>
<response>
<data>AAA</data>
</response>
</payload>
</soapenv:Body>
</soapenv:Envelope>
My response:
{"fields":{"summary":"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"><soapenv:Body>\n <payload>\n <response>\n <data>AAA</data>\n </response>\n </payload>\n </soapenv:Body></soapenv:Envelope>","project":null,"description":null,"issuetype":{"name":null}}}

How to avoid jsonObject in JSON response in wso2esb 4.9.0

Am working with Wso2esb 4.9.0,
I have a service which selects data from database and gives response in JSON format.
Proxy service:
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="GetMquestionMobile3.0"
transports="https http"
startOnLoad="true"
trace="disable"
statistics="enable">
<description/>
<target>
<inSequence onError="fault">
<property name="messageType" value="application/json" scope="axis2"/>
<property name="FORCE_ERROR_ON_SOAP_FAULT" value="true"/>
<property name="userid" expression="get-property('transport', 'userid')"/>
<property name="ModifiedOn" expression="get-property('transport', 'ModifiedOn')"/>
<property name="username" expression="get-property('transport', 'username')"/>
<property name="password" expression="get-property('transport', 'password')"/>
<property name="PartyBranchID"
expression="//FieldValue/text()"
scope="default"
type="STRING"/>
<property name="usercode"
expression="fn:substring-before(get-property('username'),'|')"
scope="default"
type="STRING"/>
<property name="clientid"
expression="fn:substring-after(get-property('username'),'|')"
scope="default"
type="STRING"/>
<payloadFactory media-type="xml">
<format>
<p:Getmquestions_Mobile xmlns:p="http://ws.wso2.org/dataservice">
<p:clientid>$1</p:clientid>
<p:modifiedon>$2</p:modifiedon>
</p:Getmquestions_Mobile>
</format>
<args>
<arg evaluator="xml" expression="get-property('clientid')"/>
<arg evaluator="xml" expression="get-property('ModifiedOn')"/>
</args>
</payloadFactory>
<send receive="MquestionMobile_Seq33.0">
<endpoint>
<address uri="http://localhost:9764/services/mquestions_DataService3.0/"
format="soap11">
<suspendOnFailure>
<errorCodes>101500,101501,101506,101507,101508,101503,50000</errorCodes>
<initialDuration>30</initialDuration>
<progressionFactor>1.0</progressionFactor>
<maximumDuration>300</maximumDuration>
</suspendOnFailure>
</address>
</endpoint>
</send>
</inSequence>
<outSequence onError="fault">
<send/>
</outSequence>
</target>
</proxy>
Sequence:
<sequence xmlns="http://ws.apache.org/ns/synapse"
name="MquestionMobile_Seq33.0"
statistics="enable">
<property name="messageType" value="application/json" scope="axis2"/>
<property name="FORCE_ERROR_ON_SOAP_FAULT" value="true"/>
<property name="HTTP_METHOD" value="POST" scope="axis2"/>
<property xmlns:ns="http://org.apache.synapse/xsd"
xmlns:s="http://ws.wso2.org/dataservice"
name="Datalist"
expression="//s:Datalist"
scope="default"
type="STRING"/>
<property xmlns:ns="http://org.apache.synapse/xsd"
xmlns:s="http://ws.wso2.org/dataservice"
name="Total"
expression="count(//s:Datalist)"
scope="default"
type="STRING"/>
<filter xmlns:ns="http://org.apache.synapse/xsd"
xpath="get-property('Total')='0.0'">
<then>
<property name="RESPONSE" value="true" scope="default" type="STRING"/>
<payloadFactory media-type="json">
<format>
{"ResponseJSON":{"Body":{"Datalist":"Not Found"},"Status":"404"}}
</format>
<args/>
</payloadFactory>
<send/>
</then>
<else>
<property name="RESPONSE" value="true" scope="default" type="STRING"/>
<property name="NO_ENTITY_BODY" scope="axis2" action="remove"/>
<payloadFactory media-type="json">
<format>{"ResponseJSON" : {"Body" :$1,"Status" :"200","Total" :"$2"}}</format>
<args>
<arg evaluator="json" expression="$.Body"/>
<arg evaluator="xml" expression="get-property('Total')"/>
</args>
</payloadFactory>
<send/>
</else>
</filter>
</sequence>
This service gives me the response as shown below
{"jsonObject":{"ResponseJSON" :
{"Body" :
{"Datalist":[
{"ComboValues":"Yes,No","QuestionType":0,"Tag":-1,"Question":"LogBooks","IsAVPT":-1,"QuestionId":989181535979317,"DataSize":-1.0,"ToolTip":-1,"IsFollowup":-1},
{"ComboValues":"Yes,No","QuestionType":0,"Tag":null,"Question":"MasterRegister","IsAVPT":-1,"QuestionId":989181536700214,"DataSize":-1.0,"ToolTip":null,"IsFollowup":-1},
{"ComboValues":null,"QuestionType":0,"Tag":null,"Question":"OthersRecords","IsAVPT":-1,"QuestionId":989181536732983,"DataSize":-1.0,"ToolTip":null,"IsFollowup":-1}]},"Status":"200","Total":"3.0"}}}
I don't want to see the jsonObject in my response, how can i avoid this in my JSON response and get the response as below
{"ResponseJSON" :
{"Body" :
{"Datalist":[
{"ComboValues":"Yes,No","QuestionType":0,"Tag":-1,"Question":"LogBooks","IsAVPT":-1,"QuestionId":989181535979317,"DataSize":-1.0,"ToolTip":-1,"IsFollowup":-1},
{"ComboValues":"Yes,No","QuestionType":0,"Tag":null,"Question":"MasterRegister","IsAVPT":-1,"QuestionId":989181536700214,"DataSize":-1.0,"ToolTip":null,"IsFollowup":-1},
{"ComboValues":null,"QuestionType":0,"Tag":null,"Question":"OthersRecords","IsAVPT":-1,"QuestionId":989181536732983,"DataSize":-1.0,"ToolTip":null,"IsFollowup":-1}]},"Status":"200","Total":"3.0"}}
DS Response:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<Body xmlns="http://ws.wso2.org/dataservice">
<Datalist>
<Question>LogBooks</Question>
<QuestionId>989181535979317</QuestionId>
<QuestionType>0</QuestionType>
<ComboValues>Yes,No</ComboValues>
<IsFollowup>-1</IsFollowup>
<IsAVPT>-1</IsAVPT>
<DataSize>-1.0</DataSize>
<ToolTip>-1</ToolTip>
<Tag>-1</Tag>
<weightage>1.00</weightage>
</Datalist>
<Datalist>
<Question>Master Register</Question>
<QuestionId>989181536700214</QuestionId>
<QuestionType>0</QuestionType>
<ComboValues>Yes,No</ComboValues>
<IsFollowup>-1</IsFollowup>
<IsAVPT>-1</IsAVPT>
<DataSize>-1.0</DataSize>
<ToolTip/>
<Tag/>
<weightage>1.00</weightage>
</Datalist>
<Datalist>
<Question>Others Records</Question>
<QuestionId>989181536732983</QuestionId>
<QuestionType>0</QuestionType>
<ComboValues/>
<IsFollowup>-1</IsFollowup>
<IsAVPT>-1</IsAVPT>
<DataSize>-1.0</DataSize>
<ToolTip/>
<Tag/>
<weightage>1.00</weightage>
</Datalist>
</Body>
</soapenv:Body>
</soapenv:Envelope>
You can use an enrich mediator to remove jsonObject from response body like below.
<enrich>
<source clone="true" xpath="$body//jsonObject//ResponseJSON"/>
<target type="body"/>
</enrich>
You can add a log mediator after enrich mediator and check the changed body.
Hope this will help you.
In side ESB mediator communications take place as SOAP messages. when you send JSON request or when ESB received JSON response what ESB does in convert that to xml / soap message by adding tag to prevent multi rooted xml.
try to use
<property name="messageType" value="application/json" scope="axis2"/>
before send / call. this will automatically remove your jsonObject from response. but if you want to convert response to xml from json then you need to manually modify using enrich mediator
make sure json formatter enabled in axis2.xml

wso2 API Manager - How to publish an API using a template?

I have been experimenting with wso2 API Manager 1.8.0 to expose a back end(http/post) system as a REST API. I am able to get it working, but I had to edit the API configuration through the Service Bus source view as pasted below. I would like to have the same template used for all of the new APIs that get published using API Publisher to ensure that we don't have to edit the service bus source every time an API get created.
Please suggest any options that you may have used..
<inSequence>
<script language="js" key="transform_script" function="buildQueryString"/>
<property name="uri.query" expression="get-property('queryString')"/>
<filter source="$ctx:AM_KEY_TYPE" regex="PRODUCTION">
<then>
<property name="Authorization"
expression="fn:concat('Basic ', base64Encode('testuser:testuser#1'))"
scope="transport"/>
<send>
<endpoint name="testuser--AddNumbers_APIsandboxEndpoint_0">
<http method="POST"
uri-template="https://testhost:8443/test/http/6731cc67-3850-4b9b-b486-62cf2a664b46?${uri.query}"/>
</endpoint>
</send>
<bam>
<serverProfile name="bam-profile">
<streamConfig name="org_wso2_apimgt_statistics_destination" version="1.0.0"/>
</serverProfile>
</bam>
</then>
<else>
<property name="Authorization"
expression="fn:concat('Basic ', base64Encode('testuser:testuser#1'))"
scope="transport"/>
<send>
<endpoint name="testuser--AddNumbers_APIsandboxEndpoint_0">
<http method="POST"
uri-template="https://testhost:8443/test/http/6731cc67-3850-4b9b-b486-62cf2a664b46?${uri.query}"/>
</endpoint>
</send>
<bam>
<serverProfile name="bam-profile">
<streamConfig name="org_wso2_apimgt_statistics_destination" version="1.0.0"/>
</serverProfile>
</bam>
</else>
</filter>
</inSequence>
<outSequence>
<payloadFactory media-type="json">
<format>
{
"apiName": "$1",
"apiVersion": "$2",
"runResponse":
{
"runId": "$3",
"runStart": "$4",
"runEnd": "$5",
"flowResponse": "$6",
"flowResult": "$7"
}
}
</format>
<args>
<arg evaluator="xml" expression="get-property('apiName')"/>
<arg evaluator="xml" expression="get-property('apiVersion')"/>
<arg evaluator="json" expression="$.runResponse.runReturn.item[0].value"/>
<arg evaluator="json" expression="$.runResponse.runReturn.item[3].value"/>
<arg evaluator="json" expression="$.runResponse.runReturn.item[4].value"/>
<arg evaluator="json" expression="$.runResponse.runReturn.item[5].value"/>
<arg evaluator="json" expression="$.runResponse.runReturn.item[6].value"/>
</args>
</payloadFactory>
<property name="messageType" value="application/json" scope="axis2"/>
<send/>
</outSequence>
There appears to be some documentation for the older versions of API Manager about the API template under <APIM_HOME>/repository/resources/api-templates/default_api_template.xml file.
With API Manager 1.8.0, I can not find the same documentation page but editing the velocity_template.xml works for non-prototype API definitions.
I am still trying to incorporate my requirements into it.
Actually you want to do some do some transformation for your message. APIM 1.8 supports mediation extension. where you can add your own in,out and fault sequence and have your transformation there. this mediation extension support for globally and per api basis. you can find the details here[1]
so if you create a global level sequence it will be applied to all apis.In your case you have to create one global insequnce to add basic oauth related stuff and one global out sequence to add payload factory related stuff
1.https://docs.wso2.com/display/AM180/Adding+Mediation+Extensions