How to make an additional http call inside api and process response? - wso2

I'm trying to create Message Mediation Policies, with which I can make an additional http call, process the response and enrich the current message. How can i do this? I use call Mediator, but I don’t understand how to handle the response.
<?xml version="1.0" encoding="UTF-8"?> <sequence name="call_out_handler" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
<call blocking="true">
<endpoint>
<http method="get" uri-template="http://192.168.99.100:8888/stubFORAPIMan/ServletWithTimeout"/>
</endpoint>
</call> </sequence>

You can use the PayloadFactory Mediator [1] to handle/format the response you received by calling an endpoint inside the Call mediator.
An example would be like this. Say you want to provide a json object by populating the values from the response you received; you can define the json object format in the "format" section and populate the values by providing the arguments in the "args" section in the PayloadFactory mediator as below.
<payloadFactory media-type="json">
<format>
{
"Data": {
"PaymentSubmissionId": "$1",
"PaymentId": "$2",
"Status": "$3",
"CreationDateTime": "$4"
}
}
</format>
<args>
<arg evaluator="xml" expression="$body//PaymentSubId"/>
<arg evaluator="xml" expression="$body//PaymentId"/>
<arg evaluator="xml" value="AcceptedSettlementInProcess"/>
<arg value="2019-06-05T15:15:22+00:00"/>
</args>
</payloadFactory>
<property name="messageType" value="application/json" scope="axis2" type="STRING"/>
[1] https://docs.wso2.com/display/EI640/PayloadFactory+Mediator

Related

how to convert xml to json in wso2

Scenario
I've implemented an API which makes a soap call to external service. I need to convert the response from xml to json (which is actually happening). But somehow I'm unable to convert the nested xml nodes to json.
API
<?xml version="1.0" encoding="UTF-8"?>
<api context="/nadra" name="NadraVerification" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST">
<inSequence>
<payloadFactory media-type="xml">
<format>
<soapenv:Envelope xmlns:nad="http://XXXX.Verification" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<nad:GetCitizenDemographics>
<nad:franchizeID>XXX</nad:franchizeID>
<nad:xml_request_data><![CDATA[
<CITIZEN_VERIFICATION><USER_VERIFICATION><USERNAME>XXXX</USERNAME><PASSWORD>XXXX</PASSWORD></USER_VERIFICATION><REQUEST_DATA><TRANSACTION_ID>$4</TRANSACTION_ID><SESSION_ID></SESSION_ID><CITIZEN_NUMBER>$5</CITIZEN_NUMBER><CONTACT_NUMBER>$6</CONTACT_NUMBER><AREA_NAME>$7</AREA_NAME></REQUEST_DATA></CITIZEN_VERIFICATION>
]]></nad:xml_request_data>
</nad:GetCitizenDemographics>
</soapenv:Body>
</soapenv:Envelope>
</format>
<args>
<arg evaluator="json" expression="$.transactionId"/>
<arg evaluator="json" expression="$.citizenNo"/>
<arg evaluator="json" expression="$.contactNo"/>
<arg evaluator="json" expression="$.areaName"/>
</args>
</payloadFactory>
<header name="Action" scope="default" value="http://XXXX.XXXX.XXXX/ICitizenVerification/GetCitizenDemographics"/>
<send>
<endpoint>
<address format="soap11" uri="https://verification.nadra.gov.pk/bioverisys/xml">
<suspendOnFailure>
<initialDuration>-1</initialDuration>
<progressionFactor>1</progressionFactor>
</suspendOnFailure>
<markForSuspension>
<retriesBeforeSuspension>0</retriesBeforeSuspension>
</markForSuspension>
</address>
</endpoint>
</send>
</inSequence>
<outSequence>
<property name="messageType" scope="axis2" type="STRING" value="application/json"/>
<payloadFactory media-type="json">
<format>
{
"status" : "success"
"response": $1
}</format>
<args>
<arg evaluator="json" expression="$.GetCitizenDemographicsResponse.GetCitizenDemographicsResult"/>
</args>
</payloadFactory>
<respond/>
</outSequence>
<faultSequence>
<payloadFactory media-type="json">
<format>
{
"status" : "failure"
}</format>
<args/>
</payloadFactory>
</faultSequence>
</resource>
</api>
Response from External Service after converting XML to JSON
{
"GetCitizenDemographicsResponse": {
"GetCitizenDemographicsResult": "<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<CITIZEN_VERIFICATION xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\r\n <RESPONSE_DATA>\r\n <RESPONSE_STATUS>\r\n <CODE>100</CODE>\r\n
<MESSAGE>successful</MESSAGE>\r\n </RESPONSE_STATUS>\r\n <SESSION_ID>00001343681312</SESSION_ID>\r\n
<CITIZEN_NUMBER>XXXX</CITIZEN_NUMBER>\r\n <PERSON_DATA>\r\n <NAME>ایوب جمال</NAME>\r\n
<FATHER_HUSBAND_NAME>XXX</FATHER_HUSBAND_NAME>\r\n <PRESENT_ADDRESS>XXXX</PRESENT_ADDRESS>\r\n
<PERMANANT_ADDRESS>XXXX</PERMANANT_ADDRESS>\r\n <DATE_OF_BIRTH>1996-01-10</DATE_OF_BIRTH>\r\n
<GENDER>male</GENDER>\r\n <EXPIRY_DATE>2030-07-11</EXPIRY_DATE>\r\n </PERSON_DATA>\r\n
</RESPONSE_DATA>\r\n</CITIZEN_VERIFICATION>"
}
}
Actual Response
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><GetCitizenDemographicsResponse xmlns="http://NADRA.Citizen.Verification"><GetCitizenDemographicsResult><?xml version="1.0" encoding="utf-16"?>
<CITIZEN_VERIFICATION xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<RESPONSE_DATA>
<RESPONSE_STATUS>
<CODE>107</CODE>
<MESSAGE>invalid citizen nummber</MESSAGE>
</RESPONSE_STATUS>
<SESSION_ID />
<CITIZEN_NUMBER>$5</CITIZEN_NUMBER>
</RESPONSE_DATA>
</CITIZEN_VERIFICATION></GetCitizenDemographicsResult></GetCitizenDemographicsResponse></s:Body></s:Envelope>
Question
My exact question is how can I convert the nested xml to json as well?. Since it has converted the first two xml nodes but the third xml node hasn't been converted.
Since you are using the Payload Factory to modify the response, you can use an XPath expression to extract the values from the soap endpoint. You don't need to explicitly convert the SOAP response to JSON using the messageType property before the Payload Factory.
Remove the messageType property
Use an XPath expression in the Payload Factory
Update Answer
According to the response from the backend, in the SOAP body, it has declared the <?xml version="1.0" encoding="UTF-8"?> tag before the CITIZEN_VERIFICATION element. Because of this, we need to first assign it to a property with OM type and then use it in the payload factory. Since we have a namespace defined for GetCitizenDemographicsResponse we need to add the namespace tag as well to the property mediator.
Option 1: With namespace
<property type="OM" xmlns:ns="http://NADRA.Citizen.Verification" expression="//ns:GetCitizenDemographicsResponse/*" name="Payload"/>
Or you can use local-name() function to get the value without defining the namespace in property mediator.
Option 2: Without defining the namespace
<property type="OM" expression="//*[local-name()='GetCitizenDemographicsResult']" name="Payload"/>
<outSequence>
<property type="OM" xmlns:ns="http://NADRA.Citizen.Verification" expression="//ns:GetCitizenDemographicsResponse/*" name="Payload"/>
<payloadFactory media-type="json">
<format>
{
"status" : "success",
"response": $1
}
</format>
<args>
<arg expression="$ctx:Payload" />
</args>
</payloadFactory>
<respond/>
</outSequence>

WSO2 EI: empty fields ("") are added as null in the payload transformation

I'm retrieving some data's from DSS by using select query and then some transformation by payload factory after that I'm passing it to an endpoint, but when I do that the empty fields are being passed as null and not as empty strings ""
"department":"{department":null}",
"Selling_dealer__c":"{Selling_dealer__c":null}"
I wish it really showed like this:
"department":"",
"Selling_dealer__c":""
Note: Also tried the synapse properties file method but not working as excepted refer link 1 refer link 2
<sequence name="LaravelConnectorSequence" xmlns="http://ws.apache.org/ns/synapse">
<payloadFactory media-type="json">
<format>
{
"screen_type": "opportunity",
"vehicle_type__c": "",
"description": "",
"audio_file_name__c": "$1",
"lead_type__c": "Phone",
"request_type__c": "",
"mobile__c": "$2",
"leadsource": "Novum",
"company__c": "N/A",
"location__c": "$3",
"department__c": "$4",
"selling_dealer__c":"$5"
}
</format>
<args>
<arg evaluator="xml"
expression="get-property('audioFileName')"
literal="false" xmlns:ns="http://org.apache.synapse/xsd"/>
<arg evaluator="xml" expression="get-property('mobile')"
literal="false" xmlns:ns="http://org.apache.synapse/xsd"/>
<arg evaluator="xml" expression="get-property('location')"
literal="false" xmlns:ns="http://org.apache.synapse/xsd"/>
<arg evaluator="xml" expression="get-property('department')"
literal="false" xmlns:ns="http://org.apache.synapse/xsd"/>
<arg evaluator="xml"
expression="get-property('selling_dealer__c')"
literal="false" xmlns:ns="http://org.apache.synapse/xsd"/>
</args>
</payloadFactory>
<log level="custom">
<property expression="json-eval($)"
name="=======Laravel Request====" xmlns:ns="http://org.apache.synapse/xsd"/>
</log>
<property expression="get-property('Novum-configs')" name="config"
scope="axis2" type="OM" xmlns:ns="http://org.apache.synapse/xsd"/>
<property expression="$axis2:config//*[local-name()='laravelToken']"
name="Authorization" scope="transport" type="STRING" xmlns:ns="http://org.apache.synapse/xsd"/>
<property expression="$axis2:config//*[local-name()='laravelURL']"
name="uri.var.laravelapi" scope="default" type="STRING" xmlns:ns="http://org.apache.synapse/xsd"/>
<call>
<endpoint>
<http method="POST" uri-template="{uri.var.laravelapi}"/>
</endpoint>
</call>
<log level="custom">
<property expression="json-eval($)"
name="=======Laravel Response====" xmlns:ns="http://org.apache.synapse/xsd"/>
</log>
Since you want to convert your null values into "" strings, one workaround would be to convert the JSON to XML and then extract the elements from that and add them to your final JSON payload. In WSO2 there are different options you can set when converting JSON payloads. You can read about different options and how to work with JSON messages from here.
Since you want null to be "". You need to set the following property. If you are on MI this needs to go into deployment.toml, if on EI this goes into synapse.properties
'synapse.commons.enableXmlNullForEmptyElement'=false
Note: In MI (Surround the property name with single quotes)
When you are extracting data from the DSS response make sure to use Xpath expressions instead of JSON path expressions. Following is a simplified version of your configurations. Note I have hardcoded the DSS response.
<?xml version="1.0" encoding="UTF-8"?>
<api context="/api" name="RESTApi" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="GET" url-mapping="/sample">
<inSequence>
<payloadFactory media-type="json">
<format>{"Selling_dealer__c": null}</format>
<args/>
</payloadFactory>
<property expression="//Selling_dealer__c" name="logInJson" scope="default" type="STRING"/>
<payloadFactory media-type="json">
<format>
{
"screen_type": "opportunity",
"selling_dealer__c": "$1"
}
</format>
<args>
<arg evaluator="xml" expression="$ctx:logInJson"/>
</args>
</payloadFactory>
<property name="messageType" scope="axis2" type="STRING" value="application/json"/>
<respond/>
</inSequence>
<outSequence/>
<faultSequence/>
</resource>
</api>
Above will produce the following response.
{
"screen_type": "opportunity",
"selling_dealer__c": "{"Selling_dealer__c":""}"
}
I used the script mediator to overcome this issue.
<script language="js"><![CDATA[var log=mc.getServiceLog();
var dep = mc.getProperty('department').toString();
var sell = mc.getProperty('selling_dealer__c').toString();
//log.info("===DepartmentValue===: "+dep);
var deps = mc.getProperty('department').startsWith("<Department");
//log.info("++++++++++++++++++++TRUE VALUE++++++++++++++++++"+deps);
if(dep.startsWith("<Department"))
{
dep ="";
mc.setProperty('department',dep);
}
//log.info("===DepartmentValueAfter===: "+dep)
//log.info("===SellingDealerValue===: "+sell);
var sells = mc.getProperty('selling_dealer__c').startsWith("<selling_dealer__c");
//log.info("++++++++++++++++++++TRUE VALUE++++++++++++++++++"+sells);
if(sell.startsWith("<selling_dealer__c"))
{
sell ="";
mc.setProperty('selling_dealer__c',sell);
}
//log.info("===selling_dealer__cValueAfter===: "+sell)
]]></script>

WSO2 EI 6.6.0 Class Mediator not being able to use SOAP call return content

I have the following API in EI 6.6.0:
<?xml version='1.0' encoding='UTF-8'?>
<api xmlns="http://ws.apache.org/ns/synapse" name="sample" context="/sample">
<resource methods="POST">
<inSequence>
<payloadFactory media-type="xml">
<format>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<P xmlns="http://tempuri.org/">
<P1>$1</P1>
<P2>$2</P2>
<P3>$3</P3>
</P>
</soap:Body>
</soap:Envelope>
</format>
<args>
<arg evaluator="json" expression="$.p1" />
<arg evaluator="json" expression="$.p2" />
<arg evaluator="json" expression="$.p3" />
</args>
</payloadFactory>
<log level="full" />
<property name="Content-Type" value="text/xml;charset=UTF-8" scope="axis2"/>
<header name="Accept" scope="transport" value="text/xml"/>
<call>
<endpoint>
<wsdl Action="name_of_the_action" service="name_of_the_service" port="name_of_soap_port" uri="http://<ip>/path?WSDL" />
</endpoint>
</call>
<class name="my_mediator_package"></class>
<log level="full" />
<payloadFactory media-type="xml">
<format>
<retorno xmlns="">
<msg>$1</msg>
</retorno>
</format>
<args>
<arg evaluator="xml" expression="get-property('property_set_on_mediator')" />
</args>
</payloadFactory>
<property name="messageType" value="application/xml" scope="axis2" type="STRING" />
<respond />
</inSequence>
<outSequence>
</outSequence>
<faultSequence>
<property name="text" value="An unexpected error occured"/>
<property name="message" expression="get-property('ERROR_MESSAGE')"/>
<payloadFactory media-type="xml">
<format>
<error xmlns="">
<msg>$1</msg>
</error>
</format>
<args>
<arg evaluator="xml" expression="get-property('ERROR_MESSAGE')"/>
</args>
</payloadFactory>
<property name="messageType" value="application/json" scope="axis2" type="STRING"/>
<respond/>
</faultSequence>
</resource>
</api>
my mediate method content:
public boolean mediate(MessageContext synCtx) {
org.apache.axis2.context.MessageContext axis2MessageContext = ((Axis2MessageContext) synCtx)
.getAxis2MessageContext();
try {
// Getting the json payload to string
String jsonPayloadToString = JsonUtil.jsonPayloadToString(((Axis2MessageContext) synCtx)
.getAxis2MessageContext());
System.out.println("original payload : \n" + jsonPayloadToString + "\n");
I'm not being able to use the return from my SOAP call in my mediator so I can work on it.
When I run the API I get the following from my mediator code:
original payload:
{}
Is there a way so I can obtain the SOAP call returned envelope and use it in my mediator?
The JSON payload is coming as empty because you are calling a SOAP backend and getting a SOAP payload. You can use synCtx.getEnvelope() in your mediator to get the SOAPEnvelope from the response.
1- make sure the json payload is there. So, log the json properties inside your inSequence.
2- I'm not being able to use the return from my SOAP call in my mediator so I can work on it. you can see the response payload in your outSequence which currently is doing nothing.
3- According to your scenario which is simply calling a SOAP webservice, you do not need a class mediator. In other words, when you do not need manipulating the initial payload and then pass it to the destination service, logically implementing your own class mediator benefits you nothing.
Also, there are quite number of samples in https://docs.wso2.com/display/EI611 which will help you.
Please let me know if your problem is solved.

How can I get the soapenv content in WSO2?

In this case, how can I get the "MyString" content in WSO2 response?
Request:
<payloadFactory media-type="json">
<format>{
"Name" : "$1",
"group": "$3"
}
</format>
<args>
<arg evaluator="xml" expression="$ctx:Name"/>
<arg evaluator="xml" expression="$ctx:group"/>
</args>
</payloadFactory>
<call>
<endpoint key="ep_Server"/>
</call>
response:
Direction: request, Envelope: <?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><text xmlns="http://ws.apache.org/commons/ns/payload">{"MyString":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOjEsIlN5c3RlbUlkIjoyMSwiUHJvcGVydHlJZCI6OSwiSXNBZG1pbiI6ZmFsc2UsIkNyZWF0ZURhdGVUaW1lIjoiMjAxNy0xMS0wOFQxMDoyMjoxMi45MDA3MjE4KzA4OjAwIn0.k6FyUGwXOAeC63oGsPWz8ttwo1LeDG3vnTbw7dJ18GY"}</text></soapenv:Body></soapenv:Envelope>
Try this.
<log>
<property name="MyString" expression="json-eval($.MyString)"></property>
</log>
Ref: https://docs.wso2.com/display/ESB500/JSON+Support
In your case the output is not json it's xml containing a text, usually it indicate that you're using text/plain type, I think the issue is there.
Moreover your output is not matching the sample code you've
Could you try to put the following before your call:
<property name="messageType" scope="axis2" type="STRING" value="application/json"/>
What is the content type that the service you're calling is returning? Is it valid? If not it could be that wso2 ei is by default considering it's text

WSO2 API manager - How to send Error/Fault message back to the Client from InSequence

I have created a REST API using WSO2 API Manager (StockQuoteService) and configured a back end SOAP based web service (converting REST to SOAP) from where it will be getting the data based on the URL template.
In the "In Sequence", I have used a Switch mediator to send the request to different back end endpoints based on incoming data whereas in the default scenario (when no case match), I want to send the error message back to the client that the "Input message is invalid".
I have tried using the Send mediator, Respond Mediator, Sequence Mediator but still no success (may be doing something wrong) as still I am getting "no response from server" error when I try to invoke the URL which doesn't match any case of Switch and goes to Default.
How can I send the Error/Fault message back to the client from In Sequence of WSO2 API Manager?
In my scenario, the input sequence I used the switch mediator and I invoke an operation or another, in the default option I create my failure response
<inSequence>
<switch xmlns:xsd="http://pharmacy.arce.org/xsd"
description=""
source="//xsd:desc">
<case regex="NATURAL">
<log description="Search Pharmacy" level="custom" separator=",">
<property name="STATUS" value="Search Pharmacy"/>
</log>
<payloadFactory media-type="xml">
<format>
<p:searchpharmacy xmlns:p="http://pharmacy.arce.org">
<ax22:pharmacy xmlns:ax22="http://pharmacy.arce.org">
<xs:desc xmlns:xs="http://pharmacy.arce.org/xsd">$1</xs:desc>
<xs:id xmlns:xs="http://pharmacy.arce.org/xsd">$2</xs:id>
<xs:latitude xmlns:xs="http://pharmacy.arce.org/xsd">$3</xs:latitude>
<xs:longitude xmlns:xs="http://pharmacy.arce.org/xsd">$4</xs:longitude>
</ax22:pharmacy>
</p:searchpharmacy>
</format>
<args>
<arg evaluator="xml" expression="//xsd:desc"/>
<arg evaluator="xml" expression="//xsd:id"/>
<arg evaluator="xml" expression="//xsd:latitude"/>
<arg evaluator="xml" expression="//xsd:longitude"/>
</args>
</payloadFactory>
<header name="To" scope="default" value="urn:searchpharmacy"/>
<log level="full" separator=",">
<property name="Mensaje" value="Cuerpo"/>
</log>
</case>
<case regex="EXPERIMENTAL">
<log description="Search Pharmacy Direction" level="custom" separator=",">
<property name="STATUS" value="Search Pharmacy Direction Request"/>
</log>
<payloadFactory media-type="xml">
<format>
<p:searchPhone xmlns:p="http://pharmacy.arce.org">
<ax22:pharmacy xmlns:ax22="http://pharmacy.arce.org">
<xs:desc xmlns:xs="http://pharmacy.arce.org/xsd">$1</xs:desc>
<xs:id xmlns:xs="http://pharmacy.arce.org/xsd">$2</xs:id>
<xs:latitude xmlns:xs="http://pharmacy.arce.org/xsd">$3</xs:latitude>
<xs:longitude xmlns:xs="http://pharmacy.arce.org/xsd">$4</xs:longitude>
</ax22:pharmacy>
</p:searchPhone>
</format>
<args>
<arg evaluator="xml" expression="//xsd:desc"/>
<arg evaluator="xml" expression="//xsd:id"/>
<arg evaluator="xml" expression="//xsd:latitude"/>
<arg evaluator="xml" expression="//xsd:longitude"/>
</args>
</payloadFactory>
<header name="Action" scope="default" value="urn:searchPhone"/>
<property name="SOAPAction" scope="transport" type="STRING" value=""/>
<log level="full" separator=",">
<property name="Data" value="Body"/>
</log>
</case>
<default>
<log description="Fault" level="custom" separator=",">
<property name="STATUS" value="Invoke fault "/>
</log>
<payloadFactory media-type="xml">
<format>
<rs:fault xmlns:rs="http://pharmacy.arce.org">
<rs:code>-1</rs:code>
<rs:type>Invocation error</rs:type>
<rs:message>No operation has been invoked</rs:message>
<rs:description>The value of the input parameter is not valid</rs:description>
</rs:fault>
</format>
<args/>
</payloadFactory>
<respond/>
</default>
</switch>
</inSequence>
Here is the default section
<default>
<log description="Fault" level="custom" separator=",">
<property name="STATUS" value="Invoke fault "/>
</log>
<payloadFactory media-type="xml">
<format>
<rs:fault xmlns:rs="http://pharmacy.arce.org">
<rs:code>-1</rs:code>
<rs:type>Invocation error</rs:type>
<rs:message>No operation has been invoked</rs:message>
<rs:description>The value of the input parameter is not valid</rs:description>
</rs:fault>
</format>
<args/>
</payloadFactory>
<respond/>
</default>
And the fault response
{"fault":{"code":-1,"type":"Invocation error","message":"No operation has been invoked","description":"The value of the input parameter is not valid"}}
You can find other scenarios here
http://harshcreationz.blogspot.com/2016/02/common-and-error-handling-sequences.html
This should work.
<payloadFactory media-type="json">
<format>
{
"error":"true",
"message":"error case"
}
</format>
</payloadFactory>
<property name="messageType" value="application/json" scope="axis2"/>
<respond/>
Nits
The error response as comments "no response from server", I receive it when I call the api from the test console that has the API Manager.
You can see this link
API Console Issue
To validate the response you expect.
Try calling from another tool such as SOAP UI or Postman, in my case I receive a fault response message with the structure defined.
This is the call from the console API
curl -X GET --header 'Accept: application/xml' --header 'Authorization: Bearer 465f1385-a120-3c19-ad22-c3057e744a3b' 'https://169.254.193.10:8252/getById/1.0.0/getEmployeeXML?Id=5'
For the call from another client in the header pass these values you have in the api call
Accept: application/json
Authorization: Bearer 465f1385-a120-3c19-ad22-c3057e744a3b'