I've created an API in WSO2 Carbon (5.0) which I POST a payload to:
{
"IdNumber" : "8008185218088",
"LastName" : null
}
I then call initiate a clone mediator sequence which forwards this payload to two different REST endpoints. The json response from the endpoints is different:
Endpoint 1 response:
{
"Name" : "Daniel",
"Number" : "12345678"
}
Endpoint 2 response:
{
"Name": "Bob",
"Address": "200 Bob Street",
"Code": "123"
}
The API response I'd like to create based on the above:
{
"Endpoint 1 Response" : {
"Name" : "Daniel",
"Number" : "12345678"
},
"Endpoint 2 Response" : {
"Name": "Bob",
"Address": "200 Bob Street",
"Code": "123"
}
}
What mediators on the outSequence do I need to configure to achieve this? How would I query the individual json response fields and combine them into a custom formatted json message for the client?
I've looked at the Aggregate mediator but I don't think it's right for differently formatted messages.
Here is my inSequence for reference:
<resource methods="POST">
<inSequence>
<property name="ROOT" scope="default">
<root:rootelement xmlns:root="www.wso2esb.com"/>
</property>
<log level="full"/>
<clone continueParent="true" id="test" sequential="true">
<target>
<sequence>
<send>
<endpoint>
<address uri="http://192.168.1.1/api/service/person" format="rest"/>
</endpoint>
</send>
</sequence>
</target>
<target>
<sequence>
<send>
<endpoint>
<address uri="http://192.168.1.1/api2/query" format="rest"/>
</endpoint>
</send>
</sequence>
</target>
</clone>
</inSequence>
You will be unable to aggregate messages like this. A solution is to use the 'call' mediator, store the first response (or the values) in a property and call the second service afterwards.
Something like this:
<call>
<endpoint>
<address uri="http://192.168.1.1/api/service/person" format="rest"/>
</endpoint>
</call>
<property name="Name1" expression="//Name" />
<property name="Number1" expression="//Number" />
<send>
<endpoint>
<address uri="http://192.168.1.1/api2/query" format="rest"/>
</endpoint>
</send>
<outSequence>
-- build message using payloadfactory
</outSequence>
You can use a payloadFactory in the outSequence to build the response message.
Related
I have few JSON Payloads that have to be appended to a JSON file.
This is how my JSON Payload will look:
{"variant": {"940894": {"attributes": {"Size": "XL" } } } }
I will be getting multiple json Payloads of this type.
At the end I need to form a file that looks like this:
[
{"variant": {"940894": {"attributes": {"Size": "XL" } } } },
{"variant": {"940895": {"attributes": {"Size": "Med" } } } },
{"variant": {"940895": {"attributes": {"Size": "Small" } } } }
]
These are the properties I have set for the requirement:
<property expression="fn:concat('Test',get-property('File_Name'),'.txt')" name="FILE_NAME" scope="default"
<propertyGroup description="File and OutputPayload properties">
<property name="messageType" scope="axis2" type="STRING" value="text/plain"/>
<property name="ContentType" scope="axis2" type="STRING" value="text/plain"/>
<property expression="$ctx:FILE_NAME" name="transport.vfs.ReplyFileName" scope="transport" type="STRING"/>
<property name="OUT_ONLY" scope="default" type="STRING" value="true"/>
</propertyGroup>
<call>
<endpoint>
<address uri="vfs:sftp://username:password/home/user/test/out/json?transport.vfs.Append=true">
<suspendOnFailure>
<initialDuration>-1</initialDuration>
<progressionFactor>1</progressionFactor>
</suspendOnFailure>
<markForSuspension>
<retriesBeforeSuspension>0</retriesBeforeSuspension>
</markForSuspension>
</address>
</endpoint>
</call>
But I get an error saying "The file type does not support append mode". What else can I try here.
I had a look at the code, and as you already noticed SFTP protocol doesn't allow you to do file appending. The supported operations for SFTP are here in the code.
Capability.CREATE, Capability.DELETE, Capability.RENAME, Capability.GET_TYPE,
Capability.LIST_CHILDREN, Capability.READ_CONTENT, Capability.URI, Capability.WRITE_CONTENT,
Capability.GET_LAST_MODIFIED, Capability.SET_LAST_MODIFIED_FILE, Capability.RANDOM_ACCESS_READ
But if you use FTP protocol instead you should be able to do File Appending as it's supported here.
Capability.CREATE, Capability.DELETE, Capability.RENAME,
Capability.GET_TYPE, Capability.LIST_CHILDREN,
Capability.READ_CONTENT, Capability.GET_LAST_MODIFIED,
Capability.URI, Capability.WRITE_CONTENT,
Capability.APPEND_CONTENT, Capability.RANDOM_ACCESS_READ
Appending works with the Local file system too.
If you want to append the file and still use SFTP you will have to READ -> APPEND -> WRITE the file. Or can consider writing a Custom Class mediator.
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}}}
I want to convert the input XML to JSON format in WSO2 ESB.
I have tried using the property mediator but it is not working,
<property name="messageType" value="application/json" scope="axis2" type="STRING"></property>
<property name="Content-Type" value="application/json" scope="transport" type="STRING"></property>
Try this configuration:
<inSequence>
...
</inSequence>
<outSequence>
<property name="messageType" value="application/json" scope="axis2"></property>
<respond/>
</outSequence>
You just need to add formatter (which is define by messageType property) to format out going message.
<property name="messageType" value="application/json" scope="axis2" type="STRING"></property>
Content-Type property is used to build incoming message to the format of the SOAP, which is used inside the ESB. If incoming message is XML you can use the following builder. Adding this property is not compulsory, if the "Content-Type" is sent with the incoming message headers ESB automatically pic it and build the message.
<property name="Content-Type" value="application/xml" scope="transport" type="STRING"></property>
Also make sure you have enable the "application/json" message formatters inside the axis2.xml file. this can be found inside the repository/conf/axis2 folder.
Let's assume your xml input is,
<name>abc</name>
<id>123</id>
Then you need to convert it to Json format as,
{
"name" : "abc",
"id" : "123"
}
You can use PayloadFactory mediator to convert XML to JSON format
<payloadFactory media-type="json">
<format>
{
"name" : "$1",
"id" : "$2"
}
</format>
<args>
<arg evaluator="xml" expression="//name"/>
<arg evaluator="xml" expression="//id"/>
</args>
</payloadFactory>
Hope this helps!!
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
PayloadFactory mediator I’m using JSON format string. The Problem is, when I enable the following lines in /repository/conf/axis2/axis2.xml, POST request works fine, but GET request produce error message.
<!--messageFormatter contentType="application/json"
class="org.apache.axis2.json.JSONStreamFormatter"/-->
<!--messageBuilder contentType="application/json"
class="org.apache.axis2.json.JSONStreamBuilder"/-->
Here is the ESB template for paypal List all Payment Resources:
<template name="listPaymentResources" xmlns="http://ws.apache.org/ns/synapse">
<sequence class="sequence">
<payloadFactory media-type="json">
<format>
{}
</format>
</payloadFactory>
<property name="messageType" scope="axis2" value="application/json" />
<call>
<endpoint>
<http method="get" uri-template="{uri.var.paypalUrl}/v1/payments/payment"/>
</endpoint>
</call>
</sequence>
</template>
Proxy service:
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="listPaymentResources"
transports="https,http"
statistics="disable"
trace="disable"
startOnLoad="true">
<target>
<inSequence>
<property xmlns:ns="uri.var.payment"
name="ppurl"
expression="//ns:paypalurl/text()"/>
<PayPal.config>
<appUri>{$ctx:ppurl}</appUri>
</PayPal.config>
<PayPal.listPaymentResources/>
<respond/>
</inSequence>
<outSequence>
<log/>
<send/>
</outSequence>
</target>
<description/>
</proxy>
The Error log:
[2013-12-11 17:25:10,971] ERROR - TargetHandler Unexpected error: Cannot get a J
SON writer
java.lang.UnsupportedOperationException: Cannot get a JSON writer
at org.apache.axis2.json.JSONStreamFormatter.getJSONWriter(JSONStreamFor
matter.java:63)
at org.apache.axis2.json.AbstractJSONMessageFormatter.getTargetAddress(A
bstractJSONMessageFormatter.java:228)
at org.apache.synapse.transport.passthru.TargetRequest.start(TargetReque
st.java:152)
at org.apache.synapse.transport.passthru.TargetHandler.requestReady(Targ
etHandler.java:136)
at org.apache.http.impl.nio.DefaultNHttpClientConnection.produceOutput(D
efaultNHttpClientConnection.java:244)
at org.apache.synapse.transport.http.conn.LoggingNHttpClientConnection.p
roduceOutput(LoggingNHttpClientConnection.java:112)
at org.apache.synapse.transport.passthru.ClientIODispatch.onOutputReady(
ClientIODispatch.java:88)
at org.apache.synapse.transport.passthru.ClientIODispatch.onOutputReady(
ClientIODispatch.java:41)
at org.apache.http.impl.nio.reactor.AbstractIODispatch.outputReady(Abstr
actIODispatch.java:148)
I have done some testing on the subject on latest release of the WSO2 ESB and i could not able to reproduce this given issue.