Invoking RESTful service from WSO2 ESB using method POST - wso2

I have a simple RESTful service that I want to expose as SOAP based Web Service using WSO2 ESB.
My simple RESTful service can be invoked like http://<<my system>>:8080/myapp/person/read
As response, I get JSON data of the Person entity.
Problem: I am not able to pass parameters to the RESTful service. I am to strip the param value from the SOAP input, but don't know how to pass it to my RESTful; service using ESB.
I have configured the following in WSO2 ESB
<proxy xmlns="http://ws.apache.org/ns/synapse" name="PersonProxy" transports="https,http" statistics="enable" trace="enable" startOnLoad="true">
<target>
<inSequence>
<property xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" name="PERSON_ID" expression="//soapenv:Body/person/id"/>
<log level="full">
<property name="PERSON_ID" expression="get-property('PERSON_ID')"/>
</log>
<filter xpath="//person">
<then>
<property name="REST_URL_POSTFIX" value="read" scope="axis2" type="STRING"/>
<property name="HTTP_METHOD" value="POST" scope="axis2" type="STRING"/>
<property name="id" expression="get-property('PERSON_ID')" scope="axis2" type="STRING"/>
<property name="ContentType" value="application/x-www-form-urlencoded" scope="axis2" type="STRING"/>
</then>
<else/>
</filter>
<send>
<endpoint>
<address uri="http://<<my system>>:8080/myapp/person" format="rest"/>
</endpoint>
</send>
</inSequence>
<outSequence>
<send/>
</outSequence>
</target>
<description></description>
</proxy>
My SOAP request looks like following
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<person>
<id>3</id>
</person>
</soapenv:Body>
</soapenv:Envelope>
I have another RESTful service with GET method and id as part of the URL itself, and that works fine. The ESB config looks like
<property name="REST_URL_POSTFIX" expression="get-property('PERSON_ID')" scope="axis2" type="STRING"/>
<property name="HTTP_METHOD" value="GET" scope="axis2" type="STRING"/>
<endpoint>
<address uri="http://<<my system>>:8080/cfs/person" format="rest"/>
</endpoint>
Appreciate any pointers or help.

If your service can be invoked as http://<<my system>>:8080/myapp/person/id, you can read the id from the SOAP request and send it using "REST_URL_POSTFIX" property as below.
<property name="REST_URL_POSTFIX" expression="//person/id" scope="axis2" type="STRING"/>
Take a look at this example which implements a similar scenario.

You can also try using the HTTP Endpoint which is new in ESB 4.7.0. You can define a URI Template much like in the REST API. Populating the template variables is done via property mediators - so anything you can do with a property mediator can be used to define the endpoint URL during mediation run time.

Related

Unable to get the response from the API

Scenario
I'm sending a request payload to the API that further calls the SMS service provider in the in-sequence flow, I need to share back the response from the SMS service provider as it is. The API works fine and I do receive SMS on phone but I'm unable to share back the response from the service provider in the out sequence flow.
The response body from my SMS service provider is actually text as shown:
The Response header of SMS Service Provider looks like this:
API
<?xml version="1.0" encoding="UTF-8"?>
<api context="/mobilink" name="MobilinkSmsApi" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST" uri-template="/send">
<inSequence>
<property action="remove" name="TRANSPORT_HEADERS" scope="axis2"/>
<property description="username" expression="json-eval($.username)" name="uri.var.username" scope="default" type="STRING"/>
<property description="password" expression="json-eval($.password)" name="uri.var.password" scope="default" type="STRING"/>
<property description="to" expression="json-eval($.to)" name="uri.var.to" scope="default" type="STRING"/>
<property description="from" expression="json-eval($.from)" name="uri.var.from" scope="default" type="STRING"/>
<property description="message" expression="json-eval($.message)" name="uri.var.message" scope="default" type="STRING"/>
<log level="full"/>
<call>
<endpoint>
<http method="post" statistics="enable" trace="enable" uri-template="https://coXXXXX.XXXX.com/sendsms_url.html?Username={uri.var.username}&Password={uri.var.password}&From={uri.var.from}&To={uri.var.to}&Message={uri.var.message}">
<suspendOnFailure>
<initialDuration>-1</initialDuration>
<progressionFactor>-1</progressionFactor>
<maximumDuration>0</maximumDuration>
</suspendOnFailure>
<markForSuspension>
<retriesBeforeSuspension>0</retriesBeforeSuspension>
</markForSuspension>
</http>
</endpoint>
</call>
</inSequence>
<outSequence>
<log category="TRACE" level="full"/>
<property description="Content-Type" name="Content-Type" scope="default" type="STRING" value="text/html"/>
<property name="messageType" scope="axis2" type="STRING" value="text/html"/>
<respond/>
</outSequence>
<faultSequence>
<log category="ERROR" level="full"/>
</faultSequence>
</resource>
</api>
Question
My Question is how to share back the response from the service provider in the out sequence? I tried to use property with value text/html and even used content-type as text/html but It didn't worked.
There are two ways to achieve this. either one of below mentioned way you can follow
place <respond/> after <call> mediator
Use <Send> mediator instead of <call>, so that flow will come from insequence to outsequence where you already placed <respond/> to send back message to client
The issue got resolved when I placed the mediator in the inSequence flow.
previously I was placing the mediator in the outSequence

Can not create new asset with WSO2 ESB

I create custom proxy service in WSO2 ESB 490:
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="write_2_greg"
transports="https,http"
statistics="disable"
trace="enable"
startOnLoad="true">
<target>
<inSequence>
<payloadFactory media-type="json">
<format>
{"name":"2rest_test","context":"/ressttest2","type":"restservice","version":"1.0.0"}
</format>
<args/>
</payloadFactory>
<property name="DISABLE_CHUNKING"
value="true"
scope="axis2"
type="STRING"/>
<property name="Accept"
expression="$trp:Accept"
scope="default"
type="STRING"/>
<property name="messageType"
value="application/json"
scope="axis2"
type="STRING"/>
<property name="Authorization"
expression="fn:concat('Basic ',base64Encode('admin:admin'))"
scope="transport"
type="STRING"/>
<call>
<endpoint>
<http trace="enable"
method="POST"
uri-template="https://localhost:9443/governance/restservices"/>
</endpoint>
</call>
<property xmlns:ns="http://org.apache.synapse/xsd"
name="__Status"
expression="$axis2:HTTP_SC"
scope="default"
type="STRING"/>
<enrich>
<source type="body" clone="true"/>
<target type="property" property="res_body"/>
</enrich>
<log level="custom">
<property name="__Status" expression="$ctx:__Status"/>
<property name="res_body--" expression="get-property('res_body')"/>
</log>
</inSequence>
<outSequence/>
<faultSequence/>
</target>
<description/>
</proxy>
This simple proxy just create new restservice to GREG, it uses the GREG REST API. But when I run this proxy service, the GREG response 500 status code, and check GREG log, it seems Jackson error:
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not construct instance of org.wso2.carbon.governance.api.generic.dataobjects.GenericArtifact, problem: abstract types can only be instantiated with additional type information
at [Source: org.apache.cxf.transport.http.AbstractHTTPDestination$1#4d4489c7; line: 1, column: 1]
at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:163)
at org.codehaus.jackson.map.deser.StdDeserializationContext.instantiationException(StdDeserializationContext.java:212)
at org.codehaus.jackson.map.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:97)
at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2376)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1166)
at org.codehaus.jackson.jaxrs.JacksonJsonProvider.readFrom(JacksonJsonProvider.java:410)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBodyReader(JAXRSUtils.java:1262)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody(JAXRSUtils.java:1209)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter(JAXRSUtils.java:757)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters(JAXRSUtils.java:716)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:253)
... 40 more
But I can create new restservice used by "Advanced Rest Client Application"(Chrome plugin)
BTW, I test this by ESB 490 , GREG 510 and GREG 520 .
How can I achive this used by ESB?
After research the carbon-governace source code, I found that the method "isReadable" in class "org.wso2.carbon.governance.rest.api.internal.GenericArtifactMessageBodyReader"
#Override
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
if (GenericArtifact.class.getName().equals(type.getName()) || GovernanceArtifact.class.getName().
equals(type.getName())) {
if (MediaType.APPLICATION_JSON_TYPE.equals(mediaType) || MediaType.APPLICATION_XML_TYPE.equals(mediaType)) {
return true;
}
}
return false;
}
When post the json to request, this method is called to determine the MediaType. The MediaType accept
application/json
But the proxy I wrote it sent the content-type
application/json; charset=UTF-8
They aren't the same, so the method return false, and not process the json post.
I try to reset the ESB proxy content type like this:
<property name="messageType" value="application/json" scope="axis2" type="STRING"/>
<property name="ContentType" scope="default" type="STRING" value="application/json"/>
But the content-type still "application/json;charset=UTF-8"
I think this is the reson, but how can we fix it ?

Callout mediator doe'snot giving any response in WSO2 ESB 4.7.0

While I am using call out mediator in wso2 esb , with DSS Endpoint I am
getting the request only, I am not getting response, even I put log in
the out sequence. Here I am sending my proxy service.
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="Binaryformat"
transports="https http"
startOnLoad="true"
trace="disable">
<description/>
<target>
<inSequence>
<property name="messageType" value="application/json" scope="axis2"/>
<property name="ContentType" value="application/json" scope="axis2"/>
<log level="full">
<property name="M1" value="*************Callout PROXY*************"/>
</log>
<callout serviceURL="http://192.168.1.201:9769/services/emp_DataService/">
<source type="envelope"/>
<target key="response"/>
</callout>
<log level="full">
<property name="Status" expression="get-property('response')"/>
</log>
<header name="To" action="remove"/>
<property name="RESPONSE" value="true"/>
<!--<property name="OUT_ONLY" value="true"/>-->
<send/>
</inSequence>
<outSequence>
<log level="full">
<property name="Status" expression="get-property('response')"/>
</log>
<payloadFactory media-type="xml">
<format>
<response>outonly</response>
</format>
<args/>
</payloadFactory>
<property name="OUT_ONLY" value="true"/>
<send/>
</outSequence>
</target>
</proxy>
I think you have configured callout mediator wrongfully. Check for the callout mediator sample here
http://docs.wso2.org/display/ESB470/Sample+430%3A+Simple+Callout+Mediator+for+Synchronized+Web+Service+Invocation
As well as OUT-ONLY set to "true" mean on a message to indicate that no response message is expected for it once it is forwarded from the ESB. you can read more about OUT_ONLY and other properties from here http://docs.wso2.org/display/ESB470/Generic+Properties
callout mediator is synchronous, it will return the response in the same sequence (your inSequence, by doing a blocking call) : your outSequence is unnecessary.
however, you should add a faultSequence to log any error
you should use tcpmon (launch tcpmon in ESB_HOME/bin) between ESB and your endpoint to verify request content going to your service and verify if you obtain a response from your service.

WSO2 ESB HTTP POST with form data

I have a soap service that I want to turn around and post a message to an external server.
I was able to do this via curl like so:
curl --data-urlencode "filename=data.txt" --data-urlencode "filedir=/home/myfile/in"
--data-urlencode "busproc=MyBP" --data-urlencode "serverip=192.168.1.4"
--data-urlencode"uid=myuserid" --data-urlencode "pwd=mypwd"
http://somelocation.com:8833/webservice/inbound/here
But I can't quite get it working correctly. Here's my proxy service:
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="ExampleHTTPPostWithFormData"
transports="http"
statistics="disable"
trace="disable"
startOnLoad="true">
<target>
<inSequence>
<log/>
<property name="messageType"
value="application/x-www-form-urlencoded"
scope="axis2"
type="STRING"/>
<property name="HTTP_METHOD" value="post" scope="axis2" type="STRING"/>
<send>
<endpoint>
<address uri="http://somelocation.com:8833/webservice/inbound/here"
format="pox"/>
<property name="uid" value="user"/>
<property name="pwd" value="password"/>
<property name="filedir" value="/home/myfile/in"/>
<property name="busproc" value="myBP"/>
<property name="serverip" value="192.168.1.4"/>
<property name="filename" value="data.txt"/>
</endpoint>
</send>
<log level="full"/>
</inSequence>
</target>
<description/>
</proxy>
The end service seems to only see me posting to the URL (but not the passed in data properties).
Properties are not the way to build the message content. The best way I've found to do it is with a payloadFactory. The message you need to build has a root XML element with one child per form field, and then it seems that Axis2 handles the messageType of application/x-www-form-urlencoded by serialising in the appropriate format. So a minimal change to your proxy would be:
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="ExampleHTTPPostWithFormData"
transports="http"
statistics="disable"
trace="disable"
startOnLoad="true">
<target>
<inSequence>
<log/>
<property name="messageType"
value="application/x-www-form-urlencoded"
scope="axis2"
type="STRING"/>
<payloadFactory media-type="xml">
<format>
<params xmlns="">
<uid>user</uid>
<pwd>password</pwd>
<filedir>/home/myfile/in</filedir>
<busproc>myBP</busproc>
<serverip>192.168.1.4</serverip>
<filename>data.txt</filename>
</params>
</format>
</payloadFactory>
<send>
<endpoint>
<address uri="http://somelocation.com:8833/webservice/inbound/here"
format="rest"/>
</endpoint>
</send>
<log level="full"/>
</inSequence>
</target>
<description/>
</proxy>
It may also be convenient to add <property name="FORCE_HTTP_1.0" value="true" scope="axis2" type="STRING"/> depending on whether your REST service handles HTTP/1.1.
If you need parameters then you can pass in arguments to the payloadFactory, using the XPath extensions. E.g.
<payloadFactory media-type="xml">
<format>
<params xmlns="">
<uid>user</uid>
<pwd>password</pwd>
<filedir>/home/myfile/in</filedir>
<busproc>myBP</busproc>
<serverip>192.168.1.4</serverip>
<filename>$1</filename>
</params>
</format>
<args>
<arg evaluator="xml" expression="$ctx:filename"/>
</args>
</payloadFactory>
If your sending the SOAP payload in a file you would need to use the VFS transport. Please refer to the following sample on how to use the VFS transport to solve your issue
http://docs.wso2.org/pages/viewpage.action?pageId=26838852
Alternatively you can use SOAPUI or any SOAP client to send the payload directly to the ESB proxy endpoint

WSO2 ESB - transform a HTTP 202 accepted response

The Endpoint_BPS_CreateCaseService/UpdateCaseService endpoints below both point to one-way BPEL services running on WSO2 BPS. WSO2 BPS returns a HTTP 202 accepted message instantly when they are invoked.
The client application that I am using will throw a fault if it does not get a valid SOAP envelope as a response so I'm going to use a proxy service in ESB to wrap around the BPEL process.
How do I use a WSO2 ESB proxy service to forward a SOAP envelope to Endpoint_BPS_* below and then return a SOAP envelope response to my client app?
I also want to execute the faultSequence "ProcessFault" if either endpoint is unavailable or times out. I previously used the OUT_ONLY to get around the response issue above but it means I can't detect endpoint problems. Unless it is possible to do both somehow?
Another thing I've tried is cloning the message but this was a bit messy.
Any help greatly appreciated
<proxy xmlns="http://ws.apache.org/ns/synapse" name="BPSProxyService" transports="https,http" statistics="disable" trace="enable" startOnLoad="true">
<target faultSequence="ProcessFault">
<inSequence>
<log level="full">
<property name="MESSAGE" value="BEGIN BPSProxyService" />
</log>
<switch source="//*[local-name()='Operation']">
<case regex="create">
<send>
<endpoint key="Endpoint_BPS_CreateCaseService" />
</send>
</case>
<case regex="update">
<send>
<endpoint key="Endpoint_BPS_UpdateCaseService" />
</send>
</case>
</switch>
</inSequence>
<outSequence>
<property name="HTTP_SC" value="200" scope="axis2" />
<class name="esb.mediators.InjectSOAPEnvelope" />
<log level="full">
<property name="MESSAGE" value="END BPSProxyService" />
</log>
<send />
<drop />
</outSequence>
</target>
<publishWSDL key="common/bpsproxyservice/bpsproxyservice.wsdl">
<resource location="schema.xsd" key="common/schema_v2.xsd" />
</publishWSDL>
</proxy>
When you receive a 'HTTP/1.1 202 Accepted' response from your backend like BPS in the outSequence of your Proxy Service, then you need the <property name="SC_ACCEPTED" value="false" scope="axis2"/> statement to modify the '202'-response into something else.
Example:
<property name="SC_ACCEPTED" value="false" scope="axis2"/>
<property name="HTTP_SC" value="200" scope="axis2"/>
<payloadFactory media-type="xml">
<format>
<response>
<result>OK</result>
</response>
</format>
<args/>
</payloadFactory>
<send/>
The response is transformed into 'HTTP/1.1 200 OK' with a response message.
Add the "FORCE_SC_ACCEPTED" parameter with the "OUT_ONLY" in the inSequence of the proxy service as follows.
<property name="FORCE_SC_ACCEPTED" value="true" scope="axis2" type="STRING"/>
<property name="OUT_ONLY" value="true" scope="default" type="STRING"/>
For more information use the following article:
http://mohanadarshan.wordpress.com/2013/05/05/out_only-scenario-in-proxy-service-wso2-esb/