We want to proxy a RESTful web service with SOAP.
The REST service uses the GET method and accepts inputs via query parameters. It produces a resource of type application/csv.
Does WSO2 ESB/Synapse support such a scenario, and is there an example available?
Example Request
SOAP Proxy Request:
<request>
<fromDate>2012-01-01</fromDate>
<toDate>2012-12-31</toDate>
</request>
REST Endpoint Request:
http://localhost/person?fromDate=2012-01-01&toDate=2012-12-31
Example Response
REST Endpoint Response
"Name","Age","Sex"
"Geoff","22","Male"
SOAP Proxy Response
<person>
<name>Geoff</name>
<age>22</age>
<sex>Male</sex>
<person>
Many thanks.
If I understand you correctly, you want to expose a REST service as a SOAP service, so that SOAP clients can access your REST service through the ESB?
If that is the case, it is possible :) You should check out sample 152 from these: http://docs.wso2.org/wiki/display/ESB451/Proxy+Service+Samples
It'll explain how you take a SOAP request and pass it to a REST backend and then transform the REST response into a SOAP response.
EDIT: Here's a sample configuration on how to do what you asked in the comments, hopefully it will get you started :)
<proxy xmlns="http://ws.apache.org/ns/synapse" name="RESTProxy" transports="https,http" statistics="disable" trace="disable" startOnLoad="true">
<target>
<inSequence>
<!-- We set the HTTP Method we want to use to make the REST request here -->
<property name="HTTP_METHOD" value="GET" scope="axis2"/>
<!-- This is where the magic happens, for what you want i.e. mapping SOAP "params" to REST query param's -->
<property name="messageType" value="application/x-www-form-urlencoded" scope="axis2"/>
<send>
<endpoint>
<!-- This is the RESTful URL we are going to query, like the one in the ESB example 152 -->
<address uri="http://localhost/person" />
</endpoint>
</send>
</inSequence>
<outSequence>
<log level="full"/>
<property name="messageType" value="text/xml" scope="axis2"/>
<send/>
</outSequence>
</target>
<description></description>
</proxy>
Then the SOAP request you make to the ESB should be something like:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<person>
<fromDate>2012-01-01</fromDate>
<toDate>2012-12-31</toDate>
</person>
</soapenv:Body>
</soapenv:Envelope>
Hope that helps :)
Hope This will be very helpful you to understand of SOAP Client and REST Service communication
http://docs.wso2.org/display/ESB460/Using+REST+with+a+Proxy+Service#UsingRESTwithaProxyService-SOAPClientandRESTService
You can use class mediator to extract the SOAP parameters using XPATH. Than build the REST URL and send it back to IN sequence flow.
1. you need to get the value from SOAP PROXY
2. you need to store it in a local variable
3. you need to pass the value to the REST SERVICE using Query Parameters
4. you need to format the response from REST Service to an SOAP Format
The SOAP Request will be,
<request>
<fromDate>2012-01-01</fromDate>
<toDate>2012-12-31</toDate>
</request>
You can store the value from SOAP PROXY Request as,
<proxy xmlns="http://ws.apache.org/ns/synapse" name="RESTProxy" transports="https,http" statistics="disable" trace="disable" startOnLoad="true><target>
<inSequence>
<property name="fromDate" expression="//fromDate" scope="default" type="STRING"/>
<property name="toDate" expression="//toDate" scope="default" type="STRING"/>
Then you can pass the values to the REST Service by,
<send>
<endpoint>
<http method="GET" uri-template="http://localhost/person?fromDate=={get-property('fromDate')}&toDate={get-property('toDate')}"/>
</endpoint>
</send>
</inSequence>
Then You can Format the Response using PayloadFactory mediator,
<outSequence>
<payloadFactory media-type="xml">
<format>
<person>
<Name>$1</Name>
<Age>$2</Age>
<Sex>$3</Sex>
</person>
</format>
<args>
<arg evaluator="json" expression="$.Name"/>
<arg evaluator="json" expression="$.Age"/>
<arg evaluator="json" expression="$.Sex"/>
</args>
</payloadFactory>
<send/>
</outSequence>
</target>
<description/>
</proxy>
So the Response of Proxy will be,
<person>
<name>Geoff</name>
<age>22</age>
<sex>Male</sex>
<person>
Related
I am new working with wso2 api manager, and I need to pause a SOAP service and take it to a REST API, I have seen all the documentation, but none responds to my problem, I already created an input sequence
getProdRequestInSequence.xml
<?xml version="1.0" encoding="UTF-8"?>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="getProdRequestInSequence" ><!-- This is the SOAP action which the backend SOAP operation expects, we set it in a header mediator --><header description="SOAPAction" name="SOAPAction" scope="transport" value="http://localhost:81/soap/products.php/query/getProd"/><!-- We are storing the input values which the end users input for these values into these two properties --><property name="uri.var.categoria" expression="$url:categoria"/>
<!-- Since we do not want the URL pattern we mentioned to be sent to the backend we need to add the below property to remove it --><property name="REST_URL_POSTFIX" scope="axis2" action="remove"/><!-- Now we need to create the actual payload which the backend requires. For that we use the payload factory mediator --><payloadFactory description="transform" media-type="xml">
<format>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:quer="http://localhost:81/soap/products.php/query/">
<soapenv:Header/>
<soapenv:Body>
<quer:getProd>
<quer:categoria>$1</quer:categoria>
</quer:getProd></soapenv:Body>
</soapenv:Envelope>
</format>
<args>
<arg expression="get-property(‘uri.var.categoria’)"/>
</args>
</payloadFactory><!-- Here we are setting the content type which the web service expects --><property description="messageProperty" name="messageType" scope="axis2" type="STRING" value="application/soap+xml"/>
</sequence>
xml_to_json_out_message.xml
<?xml version="1.0" encoding="UTF-8"?>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="xml_to_json_out_message" >
<!-- Transforms the response to a JSON -->
<property description="message" name="messageType" scope="axis2" type="STRING" value="application/json"/>
</sequence>
Now, according to the documentation, these files once created, I charge in the Message Mediation Policies, and should work perfectly
but it gives me this error
Gateway Failures
Failed to Publish Environments
Production and Sandbox
Error in deploying the sequence to gateway###
Thanks in advance for the help
getProdRequestInSequence.xml
<?xml version="1.0" encoding="UTF-8"?>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="getProdRequestInSequence" ><!-- This is the SOAP action which the backend SOAP operation expects, we set it in a header mediator --><header description="SOAPAction" name="SOAPAction" scope="transport" value="http://localhost:81/soap/products.php/query/getProd"/><!-- We are storing the input values which the end users input for these values into these two properties --><property name="uri.var.categoria" expression="$url:categoria"/>
<!-- Since we do not want the URL pattern we mentioned to be sent to the backend we need to add the below property to remove it --><property name="REST_URL_POSTFIX" scope="axis2" action="remove"/><!-- Now we need to create the actual payload which the backend requires. For that we use the payload factory mediator --><payloadFactory description="transform" media-type="xml">
<format>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:quer="http://localhost:81/soap/products.php/query/">
<soapenv:Header/>
<soapenv:Body>
<quer:getProd>
<quer:categoria>$1</quer:categoria>
</quer:getProd></soapenv:Body>
</soapenv:Envelope>
</format>
<args>
<arg expression="get-property(‘uri.var.categoria’)"/>
</args>
</payloadFactory><!-- Here we are setting the content type which the web service expects --><property description="messageProperty" name="messageType" scope="axis2" type="STRING" value="application/soap+xml"/>
</sequence>
and the output sequence
xml_to_json_out_message.xml
<?xml version="1.0" encoding="UTF-8"?>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="xml_to_json_out_message" >
<!-- Transforms the response to a JSON -->
<property description="message" name="messageType" scope="axis2" type="STRING" value="application/json"/>
</sequence>
Now, according to the documentation, these files once created, I charge in the Message Mediation Policies, and should work perfectly
but it gives me this error
Gateway Failures
Failed to Publish Environments
Production and Sandbox
Error in deploying the sequence to gateway
Thanks in advance for the help
There is a syntax mismatch in the provided getProdRequestInSequence.xml synapse configuration file.
The uri.var.categoria has been enclosed with a special character (‘) inside the get-property() method and which is not a single-quote symbol ('). Please find the updated synapse configuration file below
getProdRequestInSequence.xml
<?xml version="1.0" encoding="UTF-8"?>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="getProdRequestInSequence" >
<!-- This is the SOAP action which the backend SOAP operation expects, we set it in a header mediator -->
<header description="SOAPAction" name="SOAPAction" scope="transport" value="http://localhost:81/soap/products.php/query/getProd"/>
<!-- We are storing the input values which the end users input for these values into these two properties -->
<property name="uri.var.categoria" expression="$url:categoria"/>
<!-- Since we do not want the URL pattern we mentioned to be sent to the backend we need to add the below property to remove it -->
<property name="REST_URL_POSTFIX" scope="axis2" action="remove"/>
<!-- Now we need to create the actual payload which the backend requires. For that we use the payload factory mediator -->
<payloadFactory description="transform" media-type="xml">
<format>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:quer="http://localhost:81/soap/products.php/query/">
<soapenv:Header/>
<soapenv:Body>
<quer:getProd>
<quer:categoria>$1</quer:categoria>
</quer:getProd>
</soapenv:Body>
</soapenv:Envelope>
</format>
<args>
<arg expression="get-property('uri.var.categoria')"/>
</args>
</payloadFactory>
<!-- Here we are setting the content type which the web service expects -->
<property description="messageProperty" name="messageType" scope="axis2" type="STRING" value="application/soap+xml"/>
</sequence>
Resolution for the above-mentioned issue:
At the moment Your approach has a special character "‘" which is
common if you use a mac book for the developments. Replacing the
single quotes with the correct character will resolve your current
issues.
Recommended Approach with WSo2 API Manager :
WSO2 API Manager has the capability of exposing a SOAP Service/API as a REST API Out of the box without any sequences or synapse level configurations.
To get the REST service exposed with WSO2 API Manager you just have to provide the backend URL and the WDSL file with this feature.
Please refer to the Documentation here.
I am using WSO2 to send rest request, which I am able to do. But I would like to have some logic before I send the response to the client.
The Backend Rest service returns "Successful" as a response string. I have a Java code which used to do this, and I would like to use the same logic in WSO2. The logic is simple
1. If
the HTTP Status is greater than eq to 200 and less than 300 and resonseStr.equalsIgnoreCase("Successful") THEN
return "RetCode=C;Message=Success"
ELSE
return "RetCode=F;Message=Failed because Itegration Exception";
responseStr is the response from the Backend Rest Service.
My API looks like this:
<api xmlns="http://ws.apache.org/ns/synapse" name="TririgaApi" context="/tririga">
<resource methods="GET" url-mapping="/employee">
<inSequence>
<sequence key="conf:/tririgaConf"/>
<property name="POST_TO_URI" value="true" scope="axis2"/>
<send>
<endpoint>
<http trace="enable" method="GET" uri-template="http://{uri.var.service.host}:{uri.var.service.port}/html/en/default/rest/Integration?USERNAME={uri.var.service.user}&PASSWORD={uri.var.service.pass}&ioName={uri.var.wfname}"/>
</endpoint>
</send>
</inSequence>
</resource>
</api>
Thanks
Add an outSequence to your api and implement your mediation inside it
You can access to http status code with $axis2:HTTP_SC
You can test it's value with filter mediator
You can create a message with payloadFactory mediator
Using WSO2 ESB 4.8.1, I have configured a WSDL proxy that I want to access over REST. the proxy points to the SOAP WSDL URI and has publish WSDL turned on. This seem to work fine and I can see the service and its various operations in the WSO2 admin UI. Likewise if I go to localhost:8280/services/
The questions is how do I pass operation specific parameters when accessing over HTTP REST?
Let's say my FooService OperationX expects a "p1" parameter, can I pass this directly when accessing localhost:8280/services/FooService/OperationX in a browser?
I tried for example localhost:8280/services/FooService/SomeOperation?p1=somevalue, but always get a validation error that the required parameter is missing:
cvc-complex-type.2.4.b: The content of element 'axis2ns15:OperationXRequest' is not complete. One of '{"somenamespace":p1}' is expected.
Can this be supported by a basic WSDL proxy? Or do I need to use the API?
I think the better option for your scenario is to use api to access over REST. Here I have created an api (I used http://jsonplaceholder.typicode.com/comments as my REST back end) which gets the query parameter(postId) which was sent in REST request (http://172.22.99.96:8290/test/comments?postId=1) and assign that value to a property called mypostId inside the api.
Then I am modifying the payload by adding the mypostId property using payload factory mediator which will match to the echo service request(I have used echo service as the SOAP backend).
Then I use enrich mediator to change my soap envelope to match the echo service request soap envelope by adding "xmlns:echo="http://echo.services.core.carbon.wso2.org"" name space. Finally I am sending my created request to echo service proxy.
<api xmlns="http://ws.apache.org/ns/synapse" name="test" context="/test">
<resource methods="GET" uri-template="/comments?postId={postId}">
<inSequence>
<log level="custom">
<property name="Message Flow" value="--- Order GET ---"></property>
</log>
<log level="custom">
<property name="postId" expression="$url:postId"></property>
</log>
<property name="mypostId" expression="$url:postId"></property>
<call>
<endpoint>
<http method="GET" uri-template="http://jsonplaceholder.typicode.com/comments?postId={uri.var.postId}"></http>
</endpoint>
</call>
<payloadFactory media-type="xml">
<format>
<echo:echoInt xmlns:echo="http://echo.services.core.carbon.wso2.org">
<in>$1</in>
</echo:echoInt>
</format>
<args>
<arg evaluator="xml" expression="get-property('mypostId')"></arg>
</args>
</payloadFactory>
<log level="full"></log>
<log level="custom">
<property name="Message Flow" value="--- After Palyload factory---"></property>
</log>
<property name="extarctedBody" expression="$body"></property>
<log level="custom">
<property name="MyextarctedBody" expression="get-property('extarctedBody')"></property>
</log>
<log level="full"></log>
<enrich>
<source type="inline" clone="true">
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:echo="http://echo.services.core.carbon.wso2.org"></soapenv:Envelope>
</source>
<target type="envelope"></target>
</enrich>
<log level="custom">
<property name="Message Flow" value="--- Order GET2 ---"></property>
</log>
<log level="full"></log>
<enrich>
<source type="property" clone="true" property="extarctedBody"></source>
<target xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:echo="http://echo.services.core.carbon.wso2.org" action="child" xpath="//soapenv:Envelope"></target>
</enrich>
<log level="full"></log>
<send>
<endpoint>
<address uri="http://localhost:8290/services/echo"></address>
</endpoint>
</send>
</inSequence>
<outSequence>
<send></send>
</outSequence>
</resource>
</api>
Hope this may help you .
We are trying to implement basic SOAP-to-REST proxy service on WSO2 ESB. Our 3rd-party REST service accepts the requests in the following format:
http://<MYURL>/simpleQuery/16783484?oslc.select=value1
The problem is that operation name has numeric only format - "16783484" in our case. payloadFactory mediator does not allow having <16783484> as XML element, since XML spec restricts numeric-only element names.
<proxy xmlns="http://ws.apache.org/ns/synapse" name="CQProxy" transports="https,http" statistics="disable" trace="disable" startOnLoad="true">
<target>
<inSequence>
<payloadFactory>
<format>
<16783484>
<oslc.select>$1</oslc.select>
</16783484>
</format>
<args>
<arg value="myvalue1"/>
</args>
</payloadFactory>
<send>
<endpoint>
<address uri="http://<MYURL>/simpleQuery" format="get"/>
</endpoint>
</send>
<drop/>
</inSequence>
<outSequence>
<log level="full"/>
<send/>
</outSequence>
</target>
</proxy>
How can this be overcome?
Appreciate your help!
WSO2 support team suggested the following solution. Thank you Sandapa!
In that case, you have to set endpoint format as 'rest'. And if it's a GET request you have to set 'HTTP_METHOD' as as GET. Please refer the example given below.
Example:
<proxy xmlns="http://ws.apache.org/ns/synapse" name="CQProxy" transports="https,http" statistics="disable" trace="disable" startOnLoad="true">
<target>
<inSequence>
<property name="REST_URL_POSTFIX" value="/getSimpleQuote?symbol=IBM" scope="axis2" type="STRING"/>
<property name="HTTP_METHOD" value="GET" scope="axis2" type="STRING"/>
<send>
<endpoint>
<address uri="http://localhost:9000/services/SimpleStockQuoteService/" format="rest"/>
</endpoint>
</send>
<drop/>
</inSequence>
<outSequence>
<log level="full"/>
<send/>
</outSequence>
</target>
<description></description>
</proxy>
Although this comment is not going to suggest you a solution, I can say that this is a bad idea :-) You can try using XSLT instead of PayloadFactory to transform, but again that might choke up the XML parser. Problem is a lot of open source projects/libs that WSO2 products use and you might bump into elsewhere will honour the spec. In the long run, complying to the spec will give you less headaches when you integrate with other external tools/systems. Is it possible to change your rest service so that the service name at least have an underscore in front?
I am struggling to make work my message flow in the wso2 esb so I would need some help to implement a basic communication:
Service1 wants to receive an integer number
Service2 Generates random numbers
Service1 has InSequence: log, send (to addresspoint specified). OutSequence: log, send
this looks like:
<proxy name="ClientAskNumber" transports="https http" startOnLoad="true"
trace="disable">
<target faultSequence="fault">
<inSequence>
<log level="full">
<property name="Insequence" value="***" />
</log>
<send>
<endpoint>
<address uri="http://localhost:8280/services/RandomNumbers" />
</endpoint>
</send>
</inSequence>
<outSequence>
<log level="full">
<property name="Outsequence" value="***" />
</log>
<send />
</outSequence>
</target>
</proxy>
I have this response: <faultstring>System.Web.Services.Protocols.SoapException: Server did not recognize the value of HTTP Header SOAPAction: urn:mediate. at System.Web.Services.Protocols.Soap11ServerProtocolHelper.RouteRequest()....etc
What it means? Am I missing something else? Please help. Thank you
EDIT:
I am studying the Wso2 ESB and I just need to understand how to make work a message communication, after it I will try to add different kind of mediation. I am just breaking down the problem, because I am new to this technology and as you can see I am really struggling to make it work...
EDIT2:*
<proxy xmlns="http://ws.apache.org/ns/synapse" name="ClientAskNumber" transports="https,http" statistics="disable" trace="disable" startOnLoad="true">
<target endpoint="RandomNumbers">
<inSequence>
<log>
<property name="CLIENTASKS" value="******C_ASKS" />
</log>
<send>
<endpoint key="RandomNumbers" />
</send>
</inSequence>
<outSequence>
<log>
<property name="CLIENTRECEIVES" value="*******C_RECEIVES" />
</log>
</outSequence>
</target>
</proxy>
In the case this helps someone else: the problem with "Server did not recognize the value of HTTP Header SOAPAction: urn:mediate..." is that I needed to add an Header mediator in order to call my webservice method "getNumbers", into my InSequence as follows:
<inSequence>
<log>
<property name="CLIENTASKS" value="******C_ASKS" />
</log>
<header name="Action" value="http://tempuri.org/getNumbers" />
<send>
<endpoint key="RandomNumbers" />
</send>
</inSequence>
and send this request via soapUI:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<Numbers xmlns="http://tempuri.org/" />
</soap:Body>
</soap:Envelope>
I hope this can be useful to other persons who are using .Net Solutions with WSO2ESB (unfortunately there are not many examples out there...)
P.S. thanks to Ratha for his help
This is the flow i can tell you..
You have to point your 2nd service as the endpoint of your fist service..In the above configuration
http://localhost:8280/services/RandomNumbers --->2nd service url
ClientAskNumber -->1st service..
Now you can send the request which is needed to execute the 2nd service(ie:to retrive the random number)
So the proxy will forwrad to that endpoint and return the response to the outsequence..You should see that in the console/log since you used a log mediator.
In the error response you are getting i hope you are getting that from your second service. Check whether you are sending correct request to your endpoint