Combining multiple JSON arrays using WSO2 aggregator - wso2

I'm trying to combine two different data sources into a single data feed using WSO2 ESB. Because the different sources have different data formats my approach has been to create a proxy for each endpoint to deal with authorisation and payload formatting so that both return a JSON array. Based on research my assumption was that I could then to use the aggregator mediaor to combine the results. After working through lots of examples I have combined the two arrays successfully however one of the arrays is always duplicated. Can anyone see what I am doing wrong or does anyone have any other suggestions about a better way of achieving the combination of two JSON arrays?
I have set up the following code examples to simulate 2 feeds and then combine with my code:
<?xml version="1.0" encoding="UTF-8"?>
<proxy name="testb_url1" startOnLoad="true" trace="disable"
transports="https http" xmlns="http://ws.apache.org/ns/synapse">
<target>
<inSequence>
<payloadFactory media-type="json">
<format>[
{"id": "1",
"type": "object",
"name": "first"},
{"id": "2",
"type": "object",
"name": "second"}
]
</format>
<args/>
</payloadFactory>
<log level="full"/>
<loopback/>
</inSequence>
<outSequence>
<send/>
</outSequence>
<faultSequence/>
</target>
</proxy>
URL number 2
<?xml version="1.0" encoding="UTF-8"?>
<proxy name="testb_url2" startOnLoad="true" trace="disable"
transports="https http" xmlns="http://ws.apache.org/ns/synapse">
<target>
<inSequence>
<payloadFactory media-type="json">
<format>[
{"id": "10",
"type": "object",
"name": "ten"},
{"id": "11",
"type": "object",
"name": "eleven"}
]
</format>
<args/>
</payloadFactory>
<log level="full"/>
<loopback/>
</inSequence>
<outSequence>
<send/>
</outSequence>
<faultSequence/>
</target>
</proxy>
Code to combine:
<?xml version="1.0" encoding="UTF-8"?>
<proxy name="testb_combine" startOnLoad="true" trace="disable"
transports="https http" xmlns="http://ws.apache.org/ns/synapse">
<target>
<inSequence>
<property name="enclosing_element" scope="default">
<jsonArray xmlns=""/>
</property>
<send>
<endpoint>
<recipientlist>
<endpoint>
<address uri="http://localhost:8280/services/testb_url1/" trace="disable"/>
</endpoint>
<endpoint>
<address uri="http://localhost:8280/services/testb_url2/" trace="disable"/>
</endpoint>
</recipientlist>
</endpoint>
</send>
</inSequence>
<outSequence>
<enrich>
<source clone="true" xpath="$body/jsonArray/jsonElement"/>
<target action="child" xpath="$ctx:enclosing_element"/>
</enrich>
<aggregate>
<completeCondition>
<messageCount min="-1" max="-1"/>
</completeCondition>
<onComplete expression="$body/jsonArray/jsonElement"
enclosingElementProperty="enclosing_element">
<send/>
</onComplete>
</aggregate>
</outSequence>
<faultSequence/>
</target>
</proxy>
And returned results showing data from URL 1 duplicated:
[
{
"id": 1,
"type": "object",
"name": "first"
},
{
"id": 2,
"type": "object",
"name": "second"
},
{
"id": 1,
"type": "object",
"name": "first"
},
{
"id": 2,
"type": "object",
"name": "second"
},
{
"id": 10,
"type": "object",
"name": "ten"
},
{
"id": 11,
"type": "object",
"name": "eleven"
}
]

Remove the enrich mediator in the outsequence and it work like you want:
Proxy service:
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="testb_combine"
transports="https http"
startOnLoad="true">
<target>
<inSequence>
<property name="enclosing_element" scope="default">
<jsonArray xmlns=""/>
</property>
<send>
<endpoint>
<recipientlist>
<endpoint>
<address uri="http://localhost:8283/services/testb_url1/"/>
</endpoint>
<endpoint>
<address uri="http://localhost:8283/services/testb_url2/"/>
</endpoint>
</recipientlist>
</endpoint>
</send>
</inSequence>
<outSequence>
<aggregate>
<completeCondition>
<messageCount min="-1" max="-1"/>
</completeCondition>
<onComplete expression="$body/jsonArray/jsonElement"
enclosingElementProperty="enclosing_element">
<send/>
</onComplete>
</aggregate>
</outSequence>
<faultSequence/>
</target>
</proxy>
Response:
[
{
"id": 1,
"type": "object",
"name": "first"
},
{
"id": 2,
"type": "object",
"name": "second"
},
{
"id": 10,
"type": "object",
"name": "ten"
},
{
"id": 11,
"type": "object",
"name": "eleven"
}
]

Related

If Then else Xpath wso2

I have practice to validation alphabet and numeric. i was can validating both of them. but the return was true or false. with fn:matches combine with escape characters regex. can anyone help me to correct my validation.
My Code
<?xml version="1.0" encoding="UTF-8"?>
<api context="/a" name="A" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST">
<inSequence>
<property expression="json-eval($.OperationValueRegex.Value)" name="Value" scope="default" type="STRING"/>
<payloadFactory media-type="xml">
<format>
<OperationValueRegex xmlns="">
<Result1>$1</Result1>
</OperationValueRegex>
</format>
<args>
<arg evaluator="xml" expression="if($ctx:Value != '') then fn:tokenize($ctx:Value, ' ')[matches(., '^\d+$')]" xmlns:fn="http://www.w3.org/2005/xpath-functions"/>
</args>
</payloadFactory>
<respond/>
</inSequence>
<outSequence/>
<faultSequence/>
</resource>
</api>
Expected Result : when not input was not number there was new tag xml for description error
Sample Request:
{
"OperationValueRegex" : {
"Value" : "sadasdsadasd"
}
}
Result expected
<OperationValueRegex>
<Result1>sadasdsadasd</Result1>
<Status>the input not correct</Status>
</OperationValueRegex>
Thanks
For This requirement, you can use wso2 validate mediator. You can use the below json schema to validate the payload. You need to save this in the registry(use the media type as application/json).
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"OperationValueRegex": {
"type": "object",
"properties": {
"Value": {
"type": "number"
}
},
"required": [
"Value"
]
}
},
"required": [
"OperationValueRegex"
]
}
Then you can use the above json schema to validate the payload using validate mediator and construct the expected payload.
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="test"
startOnLoad="true"
statistics="disable"
trace="disable"
transports="http,https">
<target>
<inSequence>
<property expression="json-eval($.OperationValueRegex.Value)"
name="Value"
scope="default"
type="STRING"/>
<validate cache-schema="true">
<schema key="conf:/schema/schema.json"/>
<on-fail>
<payloadFactory media-type="xml">
<format>
<OperationValueRegex xmlns="">
<Result1>$1</Result1>
<Status>the input not correct</Status>
</OperationValueRegex>
</format>
<args>
<arg evaluator="xml" expression="$ctx:Value"/>
</args>
</payloadFactory>
<respond/>
</on-fail>
</validate>
<respond/>
</inSequence>
</target>
<description/>
</proxy>

Payload Factory exception with invalid json

If I use a payload factory to create or simply to clean the payload in case of fault, the payload factory fail with an exception.
So, in case of error, I can't manipulate the payload.
I only need to remove it for example, so the fact that is invalid for me is not influential.
Example:
<?xml version="1.0" encoding="UTF-8"?>
<api context="/DemoError" name="DemoError" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST">
<inSequence>
<payloadFactory media-type="json">
<format>{
"status":"OK"
}</format>
<args/>
</payloadFactory>
<loopback/>
</inSequence>
<outSequence>
<send/>
</outSequence>
<faultSequence>
<payloadFactory media-type="json">
<format>{
"status":"KO"
}</format>
<args/>
</payloadFactory>
</faultSequence>
</resource>
</api>
In this example, if I made a call with an invalid json...
The ESB, it goes in the fault sequence (right) but when I try in the fault to clean the payload, the payload factory fail (org.apache.synapse.commons.SynapseCommonsException: Existing json payload is malformed), the worst thing is that failing the fault sequence it return http 202...very bad
I'm using WSO2 EI 6.5.0
I tried out your API. It is not failing actually. If I add a <respond/> mediator after Payload Factory mediator inside Fault Sequence, I can see that the Fault Sequence payload is returning correctly.
I reproduced the issue, it's a little bit more complex.
If I have a validator, it goes in seems to go in the fault sequence, as expected, but now, the fault sequence fail on payload factory, returning http 202.
Try this:
<?xml version="1.0" encoding="UTF-8"?>
<api context="/DemoError" name="DemoError" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST">
<inSequence>
<validate cache-schema="true">
<schema key="gov:custom/schema.json"/>
<on-fail>
<log level="custom">
<property name="ERROR" value="VALIDATE"/>
</log>
</on-fail>
</validate>
<payloadFactory media-type="json">
<format>{
"status":"OK"
}</format>
<args/>
</payloadFactory>
<loopback/>
</inSequence>
<outSequence>
<send/>
</outSequence>
<faultSequence>
<log level="custom">
<property name="ERROR" value="I'M IN FAULT SEQUENCE"/>
</log>
<property name="HTTP_SC" scope="axis2" type="STRING" value="500"/>
<payloadFactory media-type="json">
<format>{
"status":"KO"
}</format>
<args/>
</payloadFactory>
<respond/>
</faultSequence>
</resource>
</api>
with the following schema:
{
"$id": "https://example.com/person.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "example",
"type": "object",
"required": [ "input"],
"properties": {
"input": {
"type": "boolean",
"description": "Input"
}
}
}
and the following input:
{
"input":xxx
}
This is related to the issue reported in [1]. Until a GA release includes the fix, the WUM updated versions will contain the fix for the EI versions including wso2ei-6.6.0.
[1]. https://github.com/wso2/product-ei/issues/2757

Transforming JSON array with WSO2 ESB using foreach mediator

I'm using WSO2 ESB V4.9.0 to create a proxy service for a designated end point which needs to return a transformed JSON array.
I've setup a proxy service with a foreach mediator and payloadfactory in the out sequence together with log statements to see what is happening.
The result is that each of the individual array elements is transformed as expected however the individual elements are not merged back to a single array at the end of the loop
as the documentation seems to imply. The result is that only the final element is returned.
Only thing I can see is that most of the examples I've seen don't just have an element with an array rathet than just an array. Anyone know if this is possible?
Original endpoint returns something like this:
[
{"id": "1",
"type": "object",
"name": "first",
"bounds":"[[-0.256,51.531],[-0.102,51.656]]",
"displayName": "first record"},
{"id": "2",
"type": "object",
"name": "second",
"bounds":"[[-0.256,51.531],[-0.102,51.656]]",
"displayName": "second record"},
..etc...
]
Required return from proxy service is like this:
[
{"name": "first record",
"bounds":"[[-0.256,51.531],[-0.102,51.656]]"},
{"name": "second record",
"bounds":"[[-0.256,51.531],[-0.102,51.656]]"},
..etc...
]
Actual return from proxy like this:
{"name": "first record",
"bounds":"[[-0.256,51.531],[-0.102,51.656]]"}
Configuration of the proxy is here:
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="newfeed_v2"
transports="https,http"
statistics="disable"
trace="disable"
startOnLoad="true">
<target>
<inSequence>
<log/>
</inSequence>
<outSequence>
<log level="full">
<property name="MESSAGE" value="FIRST"/>
</log>
<foreach id="foreach_1" expression="//jsonArray/jsonElement">
<sequence>
<payloadFactory media-type="json">
<format>{
"name" : "$1",
"bounds" : "$2"
}</format>
<args>
<arg evaluator="json" expression="$.displayName"/>
<arg evaluator="json" expression="$.bounds"/>
</args>
</payloadFactory>
<log level="full">
<property name="MESSAGE" value="ENDLOOP"/>
</log>
</sequence>
</foreach>
<log level="full">
<property name="MESSAGE" value="LAST"/>
</log>
<log/>
<send/>
</outSequence>
<endpoint>
<address uri="https://api.backend.com"/>
</endpoint>
</target>
<description/>
</proxy>
Can you try this as a workaround:
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="newfeed_v2"
transports="https,http"
statistics="disable"
trace="disable"
startOnLoad="true">
<target>
<inSequence>
<payloadFactory media-type="json">
<format>[
{"id": "1",
"type": "object",
"name": "first",
"bounds":"[[-0.256,51.531],[-0.102,51.656]]",
"displayName": "first record"},
{"id": "2",
"type": "object",
"name": "second",
"bounds":"[[-0.256,51.531],[-0.102,51.656]]",
"displayName": "second record"},
{"id": "4",
"type": "object",
"name": "tercero",
"bounds":"[[-0.256,51.531],[-0.102,51.656]]",
"displayName": "tercer record"}
]
</format>
<args/>
</payloadFactory>
<log level="full"/>
<loopback/>
</inSequence>
<outSequence>
<log level="full">
<property name="MESSAGE" value="FIRST"/>
</log>
<property name="Person" scope="default">
<value xmlns=""/>
</property>
<foreach id="foreach_1" expression="//jsonArray/jsonElement">
<sequence>
<payloadFactory media-type="json">
<format>{
"name" : "$1",
"bounds" : "$2"
}
</format>
<args>
<arg evaluator="json" expression="$.displayName"/>
<arg evaluator="json" expression="$.bounds"/>
</args>
</payloadFactory>
<enrich>
<source clone="true" xpath="$body//jsonObject"/>
<target action="child" xpath="$ctx:Person"/>
</enrich>
<log level="full">
<property name="MESSAGE1" value="ENDLOOP"/>
</log>
</sequence>
</foreach>
<enrich>
<source clone="true" xpath="$ctx:Person"/>
<target type="body"/>
</enrich>
<log level="full">
<property name="MESSAGE" value="ENDLOOP"/>
</log>
<!--property name="messageType" value="text/xml" scope="axis2" type="STRING"/--><log level="full">
<property name="TRANSFORMED MESSAGE" value="LAST"/>
</log>
<send/>
</outSequence>
<faultSequence/>
</target>
<description/>
</proxy>
My response:
{"value":[{"name":"first record","bounds":"[[-0.256,51.531],[-0.102,51.656]]"},{"name":"second record","bounds":"[[-0.256,51.531],[-0.102,51.656]]"},{"name":"tercer record","bounds":"[[-0.256,51.531],[-0.102,51.656]]"}]}
for each mediator will add the splitted expression to the root element so i did like this,
<api context="/foreach" name="foreach" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="GET">
<inSequence>
<payloadFactory media-type="json">
<format>[
{"id": "1",
"type": "object",
"name": "first",
"bounds":"[[-0.256,51.531],[-0.102,51.656]]",
"displayName": "first record"},
{"id": "2",
"type": "object",
"name": "second",
"bounds":"[[-0.256,51.531],[-0.102,51.656]]",
"displayName": "second record"},
{"id": "4",
"type": "object",
"name": "tercero",
"bounds":"[[-0.256,51.531],[-0.102,51.656]]",
"displayName": "tercer record"}
]
</format>
<args/>
</payloadFactory>
<log level="full">
</log>
<foreach expression="//jsonArray/jsonElement">
<sequence>
<payloadFactory media-type="xml">
<format>
<result xmlns="">
<name>$1</name>
<bounds>$2</bounds>
</result>
</format>
<args>
<arg evaluator="json" expression="$.displayName"/>
<arg evaluator="json" expression="$.bounds"/>
</args>
</payloadFactory>
</sequence>
</foreach>
<property name="messageType" scope="axis2" type="STRING" value="application/json"/>
<log level="full"/>
<respond/>
</inSequence>
<outSequence>
<send/>
</outSequence>
<faultSequence/>
</resource>
</api>
and i got the response like this
{ "result": [{"name": "first record","bounds": [[-0.256,51.531],[-0.102,51.656]]},{"name": "second record","bounds": [[-0.256,51.531],[-0.102,51.656]]},{"name": "tercer record","bounds": [[-0.256,51.531],[-0.102,51.656]]}]}

why the response is strange in wso2

I use postman to test
http://192.168.1.208:8090/jobsappName=sparkJoin001&classPath=com.mymoon.sql.SparkJoin
It's ok! It returns the message:
{
"status": "STARTED",
"result": {
"jobId": "3a47f931-f040-4e4a-a688-331f1918ae82",
"context": "6a171d9d-com.mymoon.sql.SparkJoin"
}
}
it's http status is 202!
I config in the wso2 esb and return some messages, but the browse shows the mixed message! It's stange!
The config is :
<api xmlns="http://ws.apache.org/ns/synapse" name="d" context="/dd">
<resource methods="GET" uri-template="/submit">
<inSequence>
<log level="full"/>
<payloadFactory media-type="text">
<format>{"uuid":"201456541","table": "aa/aa_table","condition":"names|91194185"}</format>
<args/>
</payloadFactory>
<send>
<endpoint>
<http method="POST" uri-template="http://192.168.1.208:8090/jobs?appName=CU&classPath=com.mymoon.ses.SparkCount"/>
</endpoint>
</send>
</inSequence>
<outSequence>
<log level="full">
<property name="asdfsadf" expression="json-eval($.)"/>
</log>
<payloadFactory media-type="text">
<format>{"jobId":"$1", "table":"$2"}</format>
<args>
<arg evaluator="json" expression="$.result.jobId"/>
<arg value="test"/>
</args>
</payloadFactory>
<send/>
</outSequence>
</resource>
</api>
So I test http://192.168.1.101:8280/dd/submit . The browser shows such message.
{
"status": "STARTED",
"result": {
"jobId": "548e9590-e442-439f-9234-223bf5bf669e",
"context": "dd803c98-com.mymoon.ses.SparkCount"
}
}{"jobId":"548e9590-e442-439f-9234-223bf5bf669e", "table":"test"}
I hope message is this:
{"jobId":"548e9590-e442-439f-9234-223bf5bf669e", "table":"test"}
So I'm confused! Help me!Thanks!
i have tested using ESB 4.8.0. i have modified your API code as follows. I tested with mock service and its working. only change i made is change media-type json from text
<api xmlns="http://ws.apache.org/ns/synapse" name="d" context="/dd">
<resource methods="GET" uri-template="/submit">
<inSequence>
<log level="full"></log>
<payloadFactory media-type="json">
<format>{"uuid":"201456541", "table": "aa/aa_table", "condition":"names|91194185" }</format>
<args></args>
</payloadFactory>
<send>
<endpoint>
<http method="post" uri-template="http://demo2965385.mockable.io/test"></http>
</endpoint>
</send>
</inSequence>
<outSequence>
<log level="full">
<property name="asdfsadf" expression="json-eval($.)"></property>
</log>
<payloadFactory media-type="json">
<format>{"jobId":"$1", "table":"$2"}</format>
<args>
<arg evaluator="json" expression="$.result.jobId"></arg>
<arg value="test"></arg>
</args>
</payloadFactory>
<send></send>
</outSequence>
</resource>
</api>
response look as follows
{
"jobId": "3a47f931-f040-4e4a-a688-331f1918ae82",
"table": "test"
}

How to concatenate JSON array values in WSO2 ESB?

We have json object as like below, Expected Result in: "(001),(011),(089),(120)".
Can anyone suggest how to iterate the json array and concat the values as mention ."(001),(011),(089),(120)"
Thanks in advance.
{
"Element": {
"Values": {
"AgentID": "aaaaa",
"TransactionData": [
{
"No": "001"
},
{
"No": "011"
},
{
"No": "089"
},
{
"No": "120"
}
]
}
}
}
You can do it by using iterate mediator, filter mediator and properties with operation scope. Try this solution. At the end you will have (001),(011),(089),(120) value in concat-data property. I have added the complete proxy for your reference.
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="StockQuoteProxy"
transports="https,http"
statistics="disable"
trace="disable"
startOnLoad="true">
<target>
<inSequence>
<payloadFactory media-type="json">
<format>
{
"Element": {
"Values": {
"AgentID": "aaaaa",
"TransactionData": [
{
"No": "001"
},
{
"No": "011"
},
{
"No": "089"
},
{
"No": "120"
}
]
}
}
}
</format>
<args/>
</payloadFactory>
<iterate continueParent="true"
expression="//Element/Values/TransactionData"
sequential="true">
<target>
<sequence>
<property name="data"
expression="json-eval($.TransactionData.No)"
type="STRING"/>
<filter source="boolean(get-property('operation','concat-data'))" regex="false">
<then>
<property name="concat-data"
expression="fn:concat('(',get-property('data'),')')"
scope="operation"
type="STRING"/>
</then>
<else>
<property name="concat-data"
expression="fn:concat(get-property('operation','concat-data'),',','(',get-property('data'),')')"
scope="operation"
type="STRING"/>
</else>
</filter>
</sequence>
</target>
</iterate>
<log level="custom">
<property name="con-cat-data"
expression="get-property('operation','concat-data')"/>
</log>
</inSequence>
<outSequence>
<send/>
</outSequence>
</target>
<publishWSDL uri="file:repository/samples/resources/proxy/sample_proxy_1.wsdl"/>
<description/>
</proxy>
Payload factory mediator is used only to simulate your scenario. If your client sends this JSON payload, then you don't need to have this payload factory mediator.
Filter mediator is used to omit the leading comma character. If you do not use a filter, you will get ,(001),(011),(089),(120) as a result (note the leading comma character). Of course, there can be other ways to remove leading comma character.
Refer this for more details on properties with operation scope.
For this kind of logic I sometimes favor the script mediator, as IMO it is simpler to implement things like string splicing/joining, conditional xml/json element building and so forth.