This site contains the documentation that is relevant to older WSO2 product versions and offerings.
For the latest WSO2 documentation, visit https://wso2.com/documentation/.

Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 16 Next »

In addition to exposing RESTful interfaces and mediating RESTful invocations by mapping REST concepts to SOAP via proxy services, you can use the WSO2 ESB REST API to configure REST endpoints in the ESB by directly specifying HTTP verbs, URL patterns, and URI templates. This page describes how you can use the REST API to handle the following use cases:

For information on securing APIs, see Securing REST APIs with Basic Auth.

Enabling REST to SOAP

In this scenario, you expose a SOAP service over REST using an ESB REST API.  


 
 

For the SOAP back-end service, we are using the StockQuote Service that is shipped with ESB. Configure and start the back-end service as described in Starting Sample Back-End Services. We will use cURL as the REST client to invoke the ESB REST API.

Following is a sample API configuration that we can used to implement this scenario.

<api name="StockQuoteAPI" context="/stockquote">
   <resource uri-template="/view/{symbol}" methods="GET">
      <inSequence>
         <payloadFactory>
        <format>
        <m0:getQuote xmlns:m0="http://services.samples">
                <m0:request>
                   <m0:symbol>$1</m0:symbol>
                </m0:request>
             </m0:getQuote>
        </format>
        <args>
        <arg expression="get-property('uri.var.symbol')"/>
        </args>
     </payloadFactory>
     <send>
        <endpoint>
        <address uri="http://localhost:9000/services/SimpleStockQuoteService" format="soap11"/>
        </endpoint>
     </send>
      </inSequence>
      <outSequence>
     <send/>
      </outSequence>
   </resource>
   <resource url-mapping="/order/*" methods="POST">
      <inSequence>
        <property name="FORCE_SC_ACCEPTED" value="true" scope="axis2"/>
    <property name="OUT_ONLY" value="true"/>
    <send>
            <endpoint>
                <address uri="http://localhost:9000/services/SimpleStockQuoteService" format="soap11"/>
            </endpoint>
         </send>
      </inSequence>      
   </resource>
</api>
</definitions>

In this API configuration we have defined two resources. One is for the HTTP method GET and the other one is for POST. 

In the first resource, we have defined the uri-template as /view/{symbol} so that request will be dispatched to this resource when you invoke the API using the following URI:

http://127.0.0.1:8280/stockquote/view/IBM 

Following is the cURL command to send this URI:

curl -v http://127.0.0.1:8280/stockquote/view/IBM

The context of this API is stockquote.

The SOAP payload required for the SOAP back-end service is constructed using the payload factory mediator defined in the inSequence. The value for the <m0:symbol> element is extracted using the following expression:

get-property('uri.var.symbol')

Here ‘symbol’ refers to the variable we defined in the uri-template (/view/{symbol}). Therefore, for the above invocation, the 'uri.var.symbol' property will resolve to the value ‘IBM’.

After constructing the SOAP payload, the request will be sent to the SOAP back-end service from the <send> mediator, which has an address endpoint defined inline with the format="soap11" attribute in the address element. The response received from the back-end soap service will be sent to the client in plain old XML (POX) format. 

In the second resource, we have defined the URL mapping as "/order/*". Since this has POST as the HTTP method, the client has to send a payload to invoke this. Following is a sample cURL command to invoke this:

curl -v -d @placeorder.xml -H "Content-type: application/xml" http://127.0.0.1:8280/stockquote/order/

Save the following sample place order request as placeorder.xml in your local file system and execute the command. This payload is used to invoke a SOAP service.  

<placeOrder xmlns="http://services.samples">
  <order>
     <price>50</price>
     <quantity>10</quantity>
     <symbol>IBM</symbol>
  </order>
</placeOrder>

You will see something similar to following line printed in the sample axis2 server (back-end server) console.

Tue Mar 19 09:30:33 IST 2013 samples.services.SimpleStockQuoteService  :: Accepted order #1 for : 10 stocks of IBM at $ 50.0

This SOAP service invocation is an OUT_ONLY invocation, so the ESB is not expecting any response back from the SOAP service. Since we have set the FORCE_SC_ACCEPTED property value to true, the ESB returns a 202 response back to the client.

Enabling REST to JMS

This section describes how a REST API can receive an HTTP message sent from a REST client and place it on a JMS queue.


  
 

The API receives the HTTP message and sends it to a JMS queue that resides in a message broker. The back-end service listens and picks up the message from this queue. For the back-end service, we are using the StockQuote Service that is shipped with ESB. Configure and start the back-end service as described in Starting Sample Back-End Services. We will use cURL as the REST client to invoke the ESB REST API.

For this sample, we use ActiveMQ 5.5.1 as the message broker. Start ActiveMQ and configure the JMS transport in ESB to work with ActiveMQ before you proceed.

Following is a sample ESB API configuration that we can used to implement this scenario:

<api xmlns="http://ws.apache.org/ns/synapse" name="RestToJmsAPI" context="/stockquote">
   <resource methods="POST" url-mapping="/order/*">
      <inSequence>
         <property name="FORCE_SC_ACCEPTED" value="true" scope="axis2"/>
         <property name="OUT_ONLY" value="true"/>
         <send>
            <endpoint>
               <address uri="jms:/SimpleStockQuoteService?transport.jms.ConnectionFactoryJNDIName=QueueConnectionFactory&java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory&java.naming.provider.url=tcp://localhost:61616" format="soap11"/>
            </endpoint>
         </send>
      </inSequence>
   </resource>
</api>

In this API configuration, we have set the OUT_ONLY property to true, as it is a one-way invocation. The message is sent to the JMS queue using the JMS Transport sender. (Note the prefix “jms” in the address endpoint URI.) Since we have set the FORCE_SC_ACCEPTED property value to true, the ESB returns a 202 response back to the client. 

Following is a sample cURL command to invoke this API:

curl -v -d @placeorder.xml -H "Content-type: application/xml" http://127.0.0.1:8280/stockquote/order/

Save the following sample place order request as "placeorder.xml" in your local file system and execute the above command.

<placeOrder xmlns="http://services.samples">
  <order>
     <price>50</price>
     <quantity>10</quantity>
     <symbol>IBM</symbol>
  </order>
</placeOrder>

You will see the something similar to the following printed in the sample axis2 server (back-end server) console:

Tue Mar 19 09:30:33 IST 2013 samples.services.SimpleStockQuoteService  :: Accepted order #1 for : 10 stocks of IBM at $ 50.0

Shut down the back-end server and execute the command again. If you go to the ActiveMQ Console and inspect the SimpleStockQuoteService queue, you will see a message queued there.

For information on enabling a JMS client to send messages to a REST back-end service, see Front-End JMS Client and Back-End REST Service.

Exposing a Back-End REST Service Using a Different API

In this scenario, we are exposing a back-end REST service using an ESB REST API. That means we are exposing a different REST API to the client for a REST back-end service.  


 
 

For the REST back-end service, we are going to use the JAX-RS Basics sample service available in the WSO2 Application Server 5.0.1. Configure and deploy the JAX-RS Basics sample by following the instructions for building and running the sample on the JAX-RS Basics page. Since we are going to run both WSO2 ESB and the WSO2 Application Server on the same machine, we have to offset the ports of Application Server by changing the offset value to 1 in <AS_HOME>/repository/conf/carbon.xml. 

Following is a sample configuration we can use to configure this scenario:

<api xmlns="http://ws.apache.org/ns/synapse" name="ClientServiceAPI" context="/clientservice">
   <resource methods="OPTIONS DELETE GET" uri-template="/clients/{id}">
      <inSequence>

         <property name="REST_URL_POSTFIX" 
expression="fn:concat('/customers/',get-property('uri.var.id'))" 
scope="axis2"/>
         <send>
            <endpoint>
               <address uri="http://localhost:9764/jaxrs_basic/services/customers/customerservice/"/>
            </endpoint>
         </send>
      </inSequence>
      <outSequence>
         <send/>
      </outSequence>
   </resource>
   <resource methods="POST PUT" uri-template="/clients">
      <inSequence>
         <property name="REST_URL_POSTFIX" value="/customers" scope="axis2"/>
         <switch source="$ctx:REST_METHOD">
            <case regex="POST">
               <payloadFactory>
                  <format>
                     <Customer xmlns="">
                        <name>$1</name>
                     </Customer>
                  </format>
                  <args>
                     <arg expression="//addClient/name"/>
                  </args>
               </payloadFactory>
            </case>
            <case regex="PUT">
               <payloadFactory>
                  <format>
                     <Customer xmlns="">
                        <id>$1</id>
                        <name>$2</name>
                     </Customer>
                  </format>
                  <args>
                     <arg expression="//updateClient/id"/>
                     <arg expression="//updateClient/name"/>
                  </args>
               </payloadFactory>
            </case>
         </switch>
         <send>
            <endpoint>
               <address uri="http://localhost:9764/jaxrs_basic/services/customers/customerservice/"/>
            </endpoint>
         </send>
      </inSequence>
      <outSequence>
         <send/>
      </outSequence>
   </resource>
</api>

The service URL for the back-end REST service is:

http://localhost:9764/jaxrs_basic/services/customers/customerservice/

The service URL for the REST API (ClientServiceAPI) is:

http://localhost:8280/clientservice/                        

As you can see, we have exposed the back-end REST service in a different context using this REST API. In addition to altering the context, the API is accepting the payload in a different format.

For the HTTP POST method, the back-end REST service accepts the payload in the following format:

<Customer>
   <name>Jack</name>
</Customer>

The ClientServiceAPI accepts the payload in the following format:

<addClient>
   <name>Jack</name>
</addClient>

For the HTTP PUT method, the back-end REST service accepts the payload in the following format:

<Customer>
   <id>123</id>
   <name>John</name>
</Customer>

The ClientServiceAPI accepts the payload in the following format:

<updateClient>
   <id>123</id>
   <name>John</name>
</updateClient>

Conversion of the payload format is done using the <payloadFactory> mediator.

We have now exposed a different REST API for the REST back-end services using an ESB REST API. In the ClientServiceAPI, there are two resources. The first resource is for the GET, OPTIONS, and DELETE HTTP methods. URL postfix is needed for the REST back-end service and is calculated using the following expression:

fn:concat('/customers/',get-property('uri.var.id'))

The calculated URL postfix is appended to the back-end service URL, as we have set that value to the REST_URL_POSTFIX property. Therefore, the final request URL will be something similar to the following:

http://localhost:9764/jaxrs_basic/services/customers/customerservice/customers/123

Following is the cURL command to send a GET request to the API:

curl -v http://localhost:8280/clientservice/clients/123 

You will see the following line printed as the response:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Customer><id>123</id><name>John</name></Customer>

The second resource is for the POST and PUT HTTP methods. The incoming REST request is filtered using the HTTP_METHOD, and the appropriate payload required for the back-end REST service is constructed using the <payloadFactory> mediator.

Following is the cURL command to send a POST request to the API:

curl -v -d @addClient.xml -H "Content-type: application/xml" http://localhost:8280/clientservice/clients 

Content of the addClient.xml file should be in the following format:

<addClient>
   <name>WSO2</name>
</addClient>

When you execute the above command in the application server console, the following line will be printed:

----invoking addCustomer, Customer name is: WSO2

Following is the cURL command to send a PUT request to the API:

curl -v -d @updateClient.xml -X PUT -H "Content-type: application/xml" http://localhost:8280/clientservice/clients

The content of the updateClient.xml file should be in the following format:

<updateClient>
    <id>123</id>
    <name>ESB</name>        
</updateClient>

When you execute the above command in the application server console, the following line will be printed:

----invoking updateCustomer, Customer name is: ESB

Transforming the Content Type

This section describes how you can transform the content type of a message using the REST API. In this scenario, the REST API exposes a REST back-end service that accepts and returns XML and JSON messages for HTTP methods as follows:

  • GET - response is in JSON format

  • POST - accepts XML request and returns response in JSON format

  • PUT - accepts JSON request and returns response in JSON format

  • DELETE - empty request body should be sent

Transformation in HTTP GET:


Transformation in HTTP POST:

Transformation in HTTP PUT:

Setting Up the Back End

For the REST back-end service, we will use a modified version of the JAX-RS Advanced sample, which is available in the WSO2 Application Server. The sample is modified to avoid complications in content types when integrating with WSO2 ESB. The only difference is that the 'serviceURL' of the sample used in this use case will be 'http://localhost:9763/StarbucksService/services/Starbucks_Outlet_Service'.

When using Application Server 5.1.0 or later, be sure to add the CXF classloading environment to the <AS_HOME>/repository/conf/tomcat/webapp-classloading.xml file as in the following configuration (see Webapp Classloading for details on configuring class loading in Application Server):

<Classloading xmlns="http://wso2.org/projects/as/classloading">
    <ParentFirst>false</ParentFirst>
    <Environments>CXF,Carbon</Environments>
</Classloading>

Since we are going to run both WSO2 ESB and the WSO2 Application Server on the same machine, offset the ports of the application server by changing the offset value to 1 in <AS_HOME>/repository/conf/carbon.xml.

To deploy the REST back-end, download the StarbucksService.war from https://svn.wso2.org/repos/wso2/people/charitham/REST-API/StarbucksService.war) and deploy it in Application Server.

REST API Configuration

Create a REST API using the following configuration:

<api name="StarbucksService" context="/Starbucks_Service">
    <resource methods="POST" url-mapping="/orders/add">
        <inSequence>
            <property name="REST_URL_POSTFIX" scope="axis2" action="remove"/>
            <send>
                <endpoint>
                    <address uri="http://localhost:9764/StarbucksService/services/Starbucks_Outlet_Service/orders/"/>
                </endpoint>
            </send>
        </inSequence>
        <outSequence>
            <log level="full"/>
            <property name="messageType" value="application/xml" scope="axis2"/>
            <send/>
        </outSequence>
    </resource>
    <resource methods="PUT" url-mapping="/orders/edit">
        <inSequence>
            <log level="full"/>
            <property name="REST_URL_POSTFIX" scope="axis2" action="remove"/>
            <property name="messageType" value="application/json" scope="axis2"/>
            <property name="ContentType" value="application/json" scope="axis2"/>
            <send>
                <endpoint>
                    <address uri="http://localhost:9764/StarbucksService/services/Starbucks_Outlet_Service/orders/"
                             format="rest"/>
                </endpoint>
            </send>
        </inSequence>
        <outSequence>
            <log level="full"/>
            <property name="messageType" value="application/xml" scope="axis2"/>
            <send/>
        </outSequence>
    </resource>
    <resource methods="DELETE GET" uri-template="/orders/{id}">
        <inSequence>
            <property name="REST_URL_POSTFIX"
                      expression="fn:concat('/orders/',get-property('uri.var.id'))"
                      scope="axis2"/>
            <send>
                <endpoint>
                    <address uri="http://localhost:9764/StarbucksService/services/Starbucks_Outlet_Service/"/>
                </endpoint>
            </send>
        </inSequence>
        <outSequence>
            <log level="full"/>
            <property name="messageType" value="application/xml" scope="axis2"/>
            <send/>
        </outSequence>
    </resource>
</api>

Executing the Sample

The context of the REST API is ‘/Starbucks_Service’. For every HTTP method, a url-mapping or url-template is defined, and the URL to call these methods differ with the defined mapping or template.

Following is the CURL command to send a GET request to the REST API:

curl -v -X GET http://localhost:8280/Starbucks_Service/orders/123

The response from the back end to the ESB will be:

{"Order":{"additions":"Milk","drinkName":"Vanilla Flavored Coffee","locked":false,"orderId":123}}

The ESB transforms this response to XML and send it back as:

<Order>
    <additions>Milk</additions>
    <drinkName>Vanilla Flavored Coffee</drinkName>
    <locked>false</locked>
    <orderId>123</orderId>
</Order>

Following is the cURL command to send an HTTP POST request to the API:

curl -v -H "Content-Type: application/xml" -X POST -d @placeOrder.xml http://localhost:8280/Starbucks_Service/orders/add

where placeOrder.xml has the following content on the order:

<Order>
    <drinkName>Mocha Flavored Coffee</drinkName>
    <additions>Caramel</additions>
</Order>

This XML request will be sent to the back end, which will send back a JSON response to the ESB:

{"Order":{"additions":"Caramel","drinkName":"Mocha Flavored Coffee","locked":false,"orderId":"d088a289-1be3-453b-ab37-7609828d2197"}}

The ESB converts this response to XML and sends it back to the client:

<Order>    <additions>Caramel</additions>
    <drinkName>Mocha Flavored Coffee</drinkName>
    <locked>false</locked>
    <orderId>d088a289-1be3-453b-ab37-7609828d2197</orderId>
</Order>

Following is the cURL command for sending an HTTP PUT request:

curl -v -H "Content-Type: application/xml" -X PUT -d @editOrder.xml http://localhost:8280/Starbucks_Service/orders/edit

where editOrder.xml has the following syntax:

<Order>
    <orderId>d088a289-1be3-453b-ab37-7609828d2197</orderId>
    <additions>Chocolate Chip Cookies</additions>
</Order>

The ESB will convert this request to JSON and send it to the back end. The response will be in JSON format:

{"Order":{"additions":"Chocolate Chip Cookies","drinkName":"Mocha Flavored Coffee","locked":false,"orderId":"d088a289-1be3-453b-ab37-7609828d2197"}}

The ESB converts this response to XML and sends it back to the client:

<Order>    <additions>Chocolate Chip Cookies</additions>
    <drinkName>Mocha Flavored Coffee</drinkName>
    <locked>false</locked>
    <orderId>d088a289-1be3-453b-ab37-7609828d2197</orderId>
</Order>

Following is the cURL command for sending an HTTP DELETE request:

curl -v -X DELETE http://localhost:8280/Starbucks_Service/orders/d088a289-1be3-453b-ab37-7609828d2197 

This request will be sent to the back end, and the order with the specified ID will be deleted.

  • No labels