As a strategic architectural component, an Enterprise Service Bus gives a range of options for service providers to improve the consumability of the services they provide. Those options allow for the reuse of existing logic as services while serving a new class of consumers. Representational state transfer “REST” utilizes the interaction capabilities classically offered by HTTP protocol. WebSphere Enterprise Service Bus, WebSphere Message Broker and WebSphere DataPower are all capable of handling HTTP requests. Hence, they all give you the capability to expose RESTful services.
The characteristics of RESTful services
In simple terms, a RESTful service should be accessible as a network-addressable resource that accepts a set of verbs defined by the implementer of that service. Those set of verbs usually map to HTTP methods (for example GET, POST, PUT and DELETE) . This mapping is the common practice, but it is not mandatory, though. The following sequence diagram shows a typical RESTful interaction where a client invokes a RESTful service passing a verb and some content (like parameters) to be processed by that service.
Figure 1. A typical RESTful interaction
Relevant Web 2.0 technologies
Since the example described in this article shows the exchange of raw data, exchanging data of JSON format and invoking the service from an AJAX client would make a special case of the example provided.
The role of the Enterprise Service Bus
An Enterprise Service Bus provide mediation capabilities to give more options both for service providers and consumers. One of the key capabilities is to change the way a service is invoked without having to make changes to the service itself. For example, using one of IBM Enterprise Service Bus products you can make existing SOAP-based web services accessible for REST clients (the article refers to this scenario as scenario #1). You may also utilize the Enterprise Service Bus capabilities to expose RESTful services as SOAP-based for web service clients (the article refers to this scenario as scenario #2). The following diagram shows the two discussed scenario with an emphasis on the fact that the mediation deployed on the Enterprise Service Bus acts as a facade to your existing assets: services or service components that realize the business logic.
Figure 2. The ESB can expose RESTful service
From a business standpoint, if you have existing services that expose all the operations required by consumers, you do not have to make changes to those services just to make them callable in a different way, e.g. to be RESTfully invoked while they are originally written for SOAP-based clients. All what is needed is to produce the right mediation artifact and make it available over the ESB for consumers.
The following sections of this article show how to implement this kind of mediation for the two scenarios using WebSphere ESB, WebSphere Message Broker and WebSphere DataPower. Then, you will see some useful tools to test those mediation artifacts you are creating. You will also see some sample consumers that are implemented using different programming platforms: Java, .NET and PHP.
Implementing the mediations
Let's see how to implement required mediations for the two scenarios mentioned above using WebSphere Enterprise Service Bus, WebSphere Message Broker and WebSphere DataPower.
Sample back end services
For this purpose of showing implementation steps, we assume two existing services: one of them is a web service that is invoked using SOAP/HTTP to be used for scenario #1, and the other one is RESTful to be used for scenario #2. The two services provide only one simple operation that takes an account number as a parameter and returns a credit score that correspond to that account number based on a trivial rule representing the business logic. The following WSDL listing shows the interface of the Web service used for scenario #1.
Listing 1. The WSDL of the sample back end service for scenario #1
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions name="AccountScore" targetNamespace="http://www.example.org/AccountScore/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.example.org/AccountScore/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <wsdl:types> <xsd:schema targetNamespace="http://www.example.org/AccountScore/"> <xsd:element name="getAccountScore"> <xsd:complexType> <xsd:sequence> <xsd:element name="accountNumber" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="getAccountScoreResponse"> <xsd:complexType> <xsd:sequence> <xsd:element name="score" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> </wsdl:types> <wsdl:message name="getAccountScoreRequest"> <wsdl:part element="tns:getAccountScore" name="parameters"/> </wsdl:message> <wsdl:message name="getAccountScoreResponse"> <wsdl:part element="tns:getAccountScoreResponse" name="parameters"/> </wsdl:message> <wsdl:portType name="AccountScore"> <wsdl:operation name="getAccountScore"> <wsdl:input message="tns:getAccountScoreRequest"/> <wsdl:output message="tns:getAccountScoreResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="AccountScoreSOAP" type="tns:AccountScore"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="getAccountScore"> <soap:operation soapAction="http://www.example.org/AccountScore/NewOperation"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="AccountScore"> <wsdl:port binding="tns:AccountScoreSOAP" name="AccountScoreSOAP"> <soap:address location= "https://localhost:9446/AccountScore/services/AccountScoreSOAP"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
The RESTful service used for scenario #2 of our example is simple servlet whose doPost() method is shown in the following listing.
Listing 2. The doPost() of the sample back end service for scenario #2
BufferedReader br = new BufferedReader(new InputStreamReader(request .getInputStream())); String inputString=br.readLine(); System.out.println(inputString); String outputString=""; if(inputString.equals("AccountNum=123")) outputString="Score=4000"; else if(inputString.equals("AccountNum=456")) outputString="Score=6000"; else outputString="Score=N/A"; OutputStream os = response.getOutputStream(); byte buffer = new byte[outputString.getBytes().length]; response.setContentType(request.getContentType()); buffer=outputString.getBytes(); os.write(buffer, 0, buffer.length); os.flush(); os.close();
To invoke this servlet, you only need to send a POST HTTP request to the URL where the servlet is deployed with a body containing the text “AccountNum=123” or “AccountNum=456”.
Note that the examples discussed in this article only handles one verb (POST) for simplicity. You may need to add further complexity at the receiving front, if there are several verbs to be supported.
The rest of this section takes you through the steps to implement the mediation for these two services to realize the two scenarios.
Using WebSphere Enterprise Service Bus
Since RESTful interactions utilize the capabilities of HTTP protocol, WebSphere Enterprise Service Bus supports RESTful interactions using normal HTTP binding. The rest of this section explains the idea and implementation of scenarios #1 and #2 on WebSphere Enterprise Service Bus.
Understanding scenario #1
To implement scenario #1, we use an export with HTTP binding to accept HTTP requests from REST clients. It is worth mentioning that you may configure the HTTP export to use one of the pre-packaged function selectors or even develop a custom one in order to make the decision on which operation should be performed based on the request message. In our example, the back end web service offers only one operation. So, no function selector is needed. You may refer to “Function selectors in export bindings” topic in the WebSphere Integration Developer Information Center.
The following illustration shows that the HTTP export is connected to a mediation flow that performs required transformation of the payload (the body of the HTTP request) sent from the REST client. As mentioned earlier, the example we show sends the data in the payload as binary data. Accordingly, the mediation flow transforms the content of the binary payload to string format to be part of the XML making the SOAP request that is passed to the back end service.
Figure 3. Providing a RESTful interface for a Web service
The mediation flow can possibly invoke different types of back ends. However, in order to implement scenario #1, the mediation flow invokes the sample back end web service using an import with web service binding.
Implementing scenario #1
This section shows the steps for implementing scenario #1 using WebSphere Integration Developer. In order to allow the Mediation module to be able to treat the HTTP request and response as binary data, a few steps have to be done before implementation.
- Make sure that you are in the Business Integration perspective. From the Business Integration view, create a mediation module, then right-click it. From the context menu select Open Dependencies. As shown below.
Figure 4. Selecting "Open Dependencies" from the context menu
- Under Predefined Resources, select Schema for predefined HTTP bytes data binding. Save your work and close the dependencies editor.
Figure 5. Selecting "Schema for predefined HTTP bytes data binding"
- Verify that two new data types are created for you under the Data Types section, as shown below.
Figure 6. The two data types created
- Create a new interface to be used to expose our newly created mediation module. The interface input and output has to be HTTPBytes type (one of the two data types created in the previous step) in order to treat the pay load as binary data.
Figure 7. The input and output of the mediation module interface should accept binary data
Now, that you have created an interface that is ready to accept binary data, you are ready to use it with an Export to expose the module over HTTP with the following steps.
- Create a new Export in the Assembly Editor and drag-and-drop the previously created interface into it.
Figure 8. Creating a new export with the created interface
- Right-click the created Export on the Assembly Editor. Select Generate Binding > HTTP Binding from the context menu.
Figure 9. Generating HTTP binding for the export
- Enter the Context path which will be part of the URL to your mediation module that represents the RESTful service. For example, the URL of the RESTful service could be http://your_server_ip:your_server_port/RestIntegration_MediationModuleWeb/Export1
Figure 10. Setting the "Context path" of the export
- Wire the export to your mediation flow primitive.
Figure 11. Wiring the export to the mediation flow
At this point, the mediation module is capable of accepting binary data over HTTP. The following steps teach you how to make the mediation module invoke a SOAP-based back end web service to complete scenario #1.
- In the Assembly Editor, drag-and-drop the WSDL file of the sample Web Service for scenario #1 onto the canvas and select Import with Web Service Binding. This step creates a new import for you based on the sample WSDL.
Figure 12. Selecting "Import with Web Service Binding"
- Wire the mediation flow primitive to the newly created import.
Figure 13. Wiring the mediation flow to the import
- Double-click your mediation flow to map the operation you are providing for the REST consumers to the operation provided by the back end web service.
Figure 14. Mapping operations between the export and the import interfaces
- Create a new Business Object Mapper primitive to the canvas , the intention of this mapper is to convert the binary input to a string and manipulate it. It will simply translates the message coming from the request operation getScore from the export to the request operation getAccountScore from the import. Other ways to do this mapping are using a Custom mediation or an XSLT primitive.
Figure 15. Creating a Business Object Mapper to hold the map for messages between the export and the import
- Create a custom map to do the mapping within the Business Object Mapper created in the previous step.
Figure 16. Creating the map for the request
Listing 3. The custom map to process the request
String inputString= new String((byte)ServiceMessageObject_body_getScore_input1_value); String accNum=inputString.split("="); ServiceMessageObject_1_body_getAccountScore_accountNumber=accNum;
- Create a similar map on the response path to convert the response string from the Web service to binary format.
Figure 17. Creating the map for the response
Listing 4. The custom map to process the response
String Score="Score="; Score+=ServiceMessageObject_body_getAccountScoreResponse_score; ServiceMessageObject_1_body_getScoreResponse_output1_value=Score.getBytes();
At this point, you have a RESTful mediation equivalent of the sample web service provided above. This mediation is accessible through the URL specified in the export (step #7) and accepts POST HTTP action. The service also does one operation that checks the credit score for an account number that is passed as a parameter in the body of the HTTP request following the format: "AccountNum=XYZ". The response is in binary that holds a string representing the credit score that corresponds to the holder of the account number specific as the parameter.
Understanding scenario #2
The implementation of scenario #2 is similar to the previous scenario in terms of the artifacts created and their use, as shown in the following figure.
Figure 18. Providing a Web service interface for a RESTful service
The only differences are that the export is using web service binding, the import is using HTTP binding and the mediation flow extracts the payload from the SOAP request and send it as binary payload to the sample back end RESTful service.
Implementing scenario #2
The following steps shows how you can use a mediation module to mediate between SOAP-based clients and RESTful back end services using WebSphere Integration Developer.
- Create a new interface to be used with the export to expose the mediation module as a Web service.
Figure 19. Creating the interface to be used with the export
- Drag-and-drop the interface onto the canvas of the Assembly Editor and choose Export with Web Service Binding.
Figure 20. Creating an export based on the interface
- Use the interface you created while implementing scenario #1 from step 1 through 4. This time you will use it with the import to invoke the sample RESTful back end service to be used for scenario #2. Drag-and-drop that interface onto the canvas and choose Import with no Binding. You are going to define the binding in the next step.
Figure 21. Creating an import
- Right-click the created import and select Generate Binding > HTTP Binding.
Figure 22. Generating HTTP binding for the import
- Specify the URL which the REST provider is addressed. For our example, we used the simple servlet of which the doPost() method is provided earlier in the article.
Figure 23. Setting the end-point URL to the address of the RESTful service
- Wire the Mediation flow with the Import and Export and you are ready to implement the mediation flow itself.
Figure 24. Wiring the export and the import to the mediation flow
At this point, you have a Web service mediation equivalent of the sample RESTful service provided above (as a simple servlet). This mediation does the same functionality that is provided by the one you created for scenario #1, yet with a SOAP-based interface.
Using WebSphere Message Broker
WebSphere Message Broker supports RESTful interactions using three primitives within a message flow: HTTPInput, HTTPRelpy and HTTPRequest. The rest of this section explains the idea and implementation of scenarios #1 and #2 on WebSphere Message Broker.
Understanding scenario #1
The implementation of scenario #1 on WebSphere Message Broker is not much different from WebSphere Enterprise Service Bus in concept. An HTTPInput node can be used to accept HTTP requests from REST clients, as shown in the following figure.
Figure 25. Providing a RESTful interface for a Web service
The HTTPInput forwards requests to a Compute node that does the required transformation of the request payload from binary to string type for any further processing you may need. The Compute node invokes the sample back end web service for scenario #1 through a SOAPRequest node to handle SOAP-based communication. An HTTPReply node constructs the HTTP response to send it back to the requesting REST client.
Implementing scenario #1
This section shows the steps for implementing scenario #1 using WebSphere Message Brokers Toolkit.
- Create a Message Flow, then drag-and-drop an HTTPInput node into the canvas and enter the Path suffix for URL for the HTTPInput which will be part of the URL address to the flow that represents the RESTful service. To access the input node for the request address would be similar to http://localhost:7080/Rest
Figure 26. Setting the "Path suffix for URL"
- Ensure the message type is Binary Large Object "BLOB" to prevent the node from parsing the payload of the incoming message from the REST client. The payload is then passed in as is (binary data) to the compute node you will create shortly.
Figure 27. The HTTPInput message domain is BLOB
- Here comes the part that invokes the sample back end Web service. Drag-and-drop the imported WSDL file of the sample back end web service for scenario #1 onto the canvas. A Service Invocation sub flow will be created for you. In order to verify creation double click on the sub-flow the invocation primitives should be available.
Figure 28. Service Invocation subflow
- Add a compute node before and after the Service Invocation to translate the message from BLOB to SOAP and vice versa. Then, place an HTTPReply node to return the required response.
Figure 29. The complete message flow
- To add the code that does the transformation, double-click the Compute node before the Service Invocation. You may use the following code snippet for this purpose.
Listing 5. The code for transforming binary payload to XML
DECLARE InputString CHARACTER; DECLARE OutString CHARACTER; DECLARE CCNum CHARACTER; SET InputString = CAST ( InputRoot.BLOB.BLOB AS CHAR CCSID 1208); SET OutString = OVERLAY(InputString PLACING '' FROM 1 FOR POSITION('=' IN InputString)); SET OutputRoot.SOAP.Body.ns:getAccountScore.accountNumber=OutString; RETURN TRUE;
- Add the code for the Compute node after the Service Invocation; as shown in listing 5 below.
Listing 6. The code for transforming SOAP to binary
DECLARE OutString CHARACTER 'Score='; Set OutString= OutString || InputRoot.XMLNSC.ns:getAccountScoreResponse.score; SET OutputRoot.BLOB.BLOB=CAST (OutString AS BLOB CCSID 1208); RETURN TRUE;
After completing the steps above, you have a RESTful mediation with the same behavior of the RESTful mediation you have created while implementing scenario #1 on WebSphere Enterprise Service Bus. The URL address of the new RESTful service is the one you specified in step #1 above.
Understanding scenario #2
WebSphere Message Broker provides SOAPInput nodes to accept SOAP-based requests from web service clients. The following figure shows that the request is then forwarded to a Compute node to do the transformation of the incoming request from SOAP to binary.
Figure 30. Providing a Web service interface for a RESTful service
The binary message is used for invoking the sample RESTful service mentioned earlier in this article to be used for scenario #2 through an HTTPRequest node. A Compute node is then used to transform the result back to SOAP that can be sent back to the requesting web service client through a SOAPReply node.
Implementing scenario #2
This section shows the steps for implementing scenario #2 using WebSphere Message Broker's Toolkit.
- 1. To expose the flow as a Web service, import the WSDL file of the sample web service into a new message set. Drag-and-drop the WSDL onto the canvas to start using it for the following steps.
Figure 31. Importing the WSDL file of the sample service
- Place a Compute node to convert the incoming message data from SOAP to BLOB (binary) so that it could be sent to the RESTful back end service.
Listing 7. The code for transforming SOAP to binary
DECLARE OutString CHARACTER 'AccountNum='; Set OutString= OutString || InputRoot.SOAP.Body.ns:getAccountScore.accountNumber; SET OutputRoot.BLOB.BLOB=CAST (OutString AS BLOB CCSID 1208); RETURN TRUE;
Listing 8. The code for transforming binary to SOAP
DECLARE InputString CHARACTER; DECLARE OutString CHARACTER; SET InputString = CAST ( InputRoot.BLOB.BLOB AS CHAR CCSID 1208); SET OutString = OVERLAY(InputString PLACING '' FROM 1 FOR POSITION('=' IN InputString)); Set OutputRoot.XMLNSC.ns:getAccountScoreResponse.score=OutString; RETURN TRUE;
Figure 32. Adding a compute node to transform from SOAP to BLOB
- Place a HTTPRequest node that will invoke the sample backend RESTful service.
Figure 33. Adding an HTTPRequest node
- For the HTTPRequest node, enter the URL address of the RESTful service. For our example, we used the simple servlet of which the doPost() method is provided earlier in the article.
Figure 34. Specifying the back end service endpoint
- Finally, place a place a Compute node to convert the response coming from the back end RESTful service to SOAP response to be sent to the calling web service client through a SOAPReply node you add.
Figure 35. Adding a Compute node and a SOAPReply node
At this point, you have a Web service equivalent of that behaves exactly as the one that you have created earlier using WebSphere Enterprise Service Bus while implementing scenario #2.
Using WebSphere DataPower
WebSphere DataPower supports RESTful interactions in different ways. This section explains one way for implementing scenarios #1 and #2 on WebSphere DataPower.
Understanding scenario #1
There are several ways to implement scenario #1. We show here a recommended way of implementation that uses an XML Firewall to accept HTTP requests from the REST client, as shown below.
Figure 36. Providing a RESTful interface for a Web service
Since, the incoming requests contain binary payload, the XML Firewall will use a WebSphere Transformation Extender map to transform that binary payload to SOAP that can be accepted by web services. Another transformation is also done the opposite way by transforming the SOAP reply from the web service to binary that can be sent to the requesting REST client. In addition to those transformations, the XML Firewall uses XSLT function to invoke the back end web service via a Web Service Proxy. Therefore, in this scenario we use the loop back option for the XML Firewall. Alternatively, this could have been achieved using a static back end that calls the Web Service Proxy.
For another variation of this implementation without handling binary payload, you may refer to the following article: http://www.ibm.com/developerworks/websphere/techjournal/0903_peterson/0903_peterson.html.
Implementin scenario #1
This section shows you the steps required to implement scenario #1 on WebSphere DataPower. First, you do the map to transform between binary and XML. Then you configure the Web Service Proxy to handle the communication with the back end web service. Finally, you use the map you have created with the XML Firewall that is responsible for receiving REST requests, transform the payload from binary to XML and feed it in to the Web Service Proxy which in turn pass it to the sample backend web service.
Let's first build two Type Trees using WebSphere Transformation Extender Design Studio in order to define incoming request message and the SOAP messages sent to sample back end web service would look like.
For the non-xml input we will generate the type tree manually, we expect the input to come in this form AccountID=123.
- Create a new Type Tree for the incoming messages from the REST client which you will treat as binary (also known as non-XML).
Figure 37. Creating the Type Tree
- Create one Group and two Items under the newly created Type Tree, as shown below.
Figure 38. Creating descendants
- Since the payload from the REST client is expected to be of the format
AccountNum=123, set the terminator for Item named "Property" to be "=", so that WTX engine will interpret the part before the '=' sign to be of type "Property", and locate the value to be the part after that equals sign.
Figure 39. Defining the separator
- Select Tree > Analyze, then Save.
- Create another Type Tree for the SOAP message to be sent to the sample back end web service. You can create this Type Tree by importing the WSDL file of the sample back end web service.
Figure 40. Importing the WSDL of the back end service
- Accept default values, till you press Finish button. Open the generated tree, then Analyze and Save.
At this point you have created the two Map Type Tree (MTT) files. In the following steps, you will find them as Binary.mtt for the one that describes the binary message from the client and AccountScore.mtt for the one the describes the message based on the WSDL file of the sample back end web service. You are ready now to use those Type Trees to create the Map itself by following the steps below.
- Create a new map with an Input Card and one Output Card as shown below.
Figure 41. Creating a new map
- Set properties for the Input Card "Binary" to the values shown below, where binary.txt is a text file that has the content of AccountID=123 for testing purposes. Note that you are setting the Type Tree property to the name of the Type Tree you have created earlier for the binary messages.
Figure 42. Setting the properties of the Input Card
- Set properties for the Output Card "XML_OUT" as shown below. This one uses the other Type Tree that you have created earlier for the SOAP-based web service messages.
Figure 43. Setting the properties of the Output Card
- Complete the mapping using the values shown below.
Figure 44. Mapping the fields
- Select Map > Build, the Map > Run to test map.
- Change the MapRuntime property of the Map Settings of the map to DataPower instead of WebSphere Transformation Extender, so that the compiled map is deployable to DataPower with ".dpa" extension. You may call the file "BinaryToXML.dpa", for example. Select Map > Build to generate the file.
Figure 45. Preparing for deployment
Now that you have all the required type mapping done, you are ready to deploy the artifacts you created on the WebSphere DataPower SOA appliance. Before you can apply the mapping you are going to create a Web Service Proxy and an XML Firewall on WebSphere DataPower by following the steps below.
- From Control Panel, click on Web Service Proxy icon, then click Add. Type in the Web Service Proxy name, e.g. WS-BinaryToSOAP and click Create Web Service Proxy button.
- If you do not already have the WSDL of the sample back end web service uploaded, enter the File to upload and click Upload.
Figure 46. Uploading the WSDL file
- After uploading the file, click Next.
Figure 47. Completing the Web Service Proxy configurations
- Create a new Front Side Handler. Assign an IP, Port, and the verbs to support, then click Add.
Figure 48. Creating a Front Side Handler
- Before you click Next, set the IP, port and Remote URI for the back end sample web service.
The Web Service Proxy is now configured and is ready to invoke the sample back end service. The following steps shows you how to configure a loop back XML Firewall that should feed in the incoming requests to the Web Service Proxy you have just created.
- From the DataPower Control Panel choose XML Firewall. Then, click Add.
- Select Pass Thru, as shown below. Then click Next.
Figure 49. Creating a loop back XML Firewall
- Enter a name. RESTtoSOAPService, for example.
- Select the Firewall Type to be loopback-proxy.
- Enter the Device Address and port that will receive incoming client requests. It's not encouraged to set the IP to be 0.0.0.0. Click Next.
Figure 50. Setting the address of the XML Firewall
- Select Commit, then Done.
- Open the XML Firewall settings and change the Request Type to be Non-XML, since we expect binary payload from the REST client.
- Open the Firewall Policy to edit it. There are four actions as discussed below.
Figure 51. Editing the XML Firewall Policy
- A Match Rule, which accepts all incoming requests for any URI on the specified IP address and port.
- A Binary Transformation action, which calls one of the WTX maps that was created in an earlier step, it converts the the binary input to a SOAP Request, as shown below.
Figure 52. Configuring the Transform Binary action
- A Transformation action that uses a simple XSLT to call the sample back end service via the Web Service Proxy, and creates the response message to be sent back to the requesting client. The style sheet for this transformation is shown below.
Listing 9. The style sheet that calls the Web Service Proxy
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:dp="http://www.datapower.com/extensions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" extension-element-prefixes="dp" exclude-result-prefixes="dp" version="1.1"> <xsl:template match="/"> <xsl:copy-of select="dp:soap-call('http://the_address_of_wsproxy:the_port _of_wsproxy/mockAccountScoreSOAP',/,'',0)"/> </xsl:template> </xsl:stylesheet>
- A Binary transformation action that uses an XSL sheet that transform the SOAP response to a non-XML response to be sent to the client. The style sheet for this transformation is shown below.
Listing 10. The style sheet that transforms from SOAP to binary
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> <xsl:output method="text"/> <xsl:template match="/">score=<xsl:value-of select="//score"/> </xsl:template> </xsl:stylesheet>
By doing the steps above, you have a RESTful service with the same behavior of the RESTful service you created while implementing scenario #1 on WebSphere Enterprise Service Bus and WebSphere Message Broker. The URL address of the new RESTful service is for the XML Firewall.
Understanding scenario #2
For scenario #2, we basically swap the Web Service Proxy and the XML Firewall with each other, as shown below.
Figure 53. Providing a Web service interface for a RESTful service
The Web Service Proxy accepts SOAP requests from web service clients based on the WSDL of the sample back end web service, then passes the request to the XML Firewall to performs required transformation between SOAP and binary. The XML Firewall also invokes the sample back end RESTful service.
Implementing scenario #2
As you did for scenario #1, you will begin by creating the artifacts required to do the mapping between XML-based and binary content using WebSphere Transformation Extender Design Studio. Fortunately, you can use the two type trees created for scenario #1. You will use them differently, though. The following steps shows you how to create a Response Map to do the mapping from binary response returned from the sample back end RESTful service to SOAP so that it can be sent back to the requesting web service client through the Web Service Proxy.
- Follow the same steps as you did for the creation of request map in scenario #1 to create a Response Map. For the XML_OUT Output Card, selec the Envelope group for the response as in snapshot below.
Figure 54. Creating the Response Map
- Complete the mapping as shown below. You may also select Rules > Insert NONE if Empty to automatically set empty fields to NONE.
Figure 55. Mapping the fields
- Select Map > Build, the Map > Run to test map.
- Change the MapRuntime to WebSphere DataPower from Map Settings, as you did in scenario #1.
At this point, the mapping artifacts are ready to be used for WebSphere DataPower. The following steps show the required configurations on WebSphere DataPower.
To create the Web Service Proxy follow the same steps you did for scenario #1. However, instead of setting the back end to a Web service, set it to the IP Address and Port of the XML Firewall you will create below, which will transform the SOAP request/response from to binary so that it can communicate with the sample back end RESTful service.
You also will need to create an XML Firewall. The following steps show the details.
- Create the new XML Firewall with a static back end (instead of the loopback you used for scenario #1). Enter the Server Address and Port of the server that hosts the sample back end RESTful service.
Figure 56. Creating a Pass Thru XML Firewall
- Open the newly created XML Firewall and set Request Type for front end to SOAP, and for backend to Non-XML.
- Open Processing Policy to create a Request Rule and a Response Rule, as follow.
- For the Request Rule define the following actions.
- For the Response Rule create only a Binary Transformation action that uses the WebSphere Transformation Extender Response Map you created to transforms the binary response to a SOAP response to be sent to the requesting web service client through the Web Service Proxy.
Figure 57. Editing the XML Firewall Policy for the Request
Listing 11. Example
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> <xsl:output method="text"/> <xsl:template match="/">AccountID=<xsl:value-of select="//accountNumber"/> </xsl:template> </xsl:stylesheet>
Figure 58. Editing the XML Firewall Policy for the Response
At this point, you have a web service equivalent of that behaves exactly as the one that you have created earlier using WebSphere Enterprise Service Bus and WebSphere Message Broker while implementing scenario #2.
Testing the service providers
Now that you have dealt with different interfaces for services, some of them is SOAP-based and some are RESTful, you will see some sample tools to make sure these service are working properly. Although, it is not a comprehensive list of tools, you may find them useful to test both: the mediations you have created and the back end services, as well. The following illustration shows a summary of the tools we are discussing and their proper use for testing the service providers based on the two scenarios you implemented.
Figure 59. Using the tools to test service providers
The TCP/IP Monitor is useful utility that come with WebSphere Integration Developer , several other Rational Software Delivery products and the underlying Eclipse platform. TCP/IP Monitor allows you to monitor the traffic between a client and an application server. You may use TCP/IP Monitor to see the traffic to and from the RESTful services and the web services you have created in this article. The following steps shows an example of monitoring the traffic between a RESTful client and service provider using WebSphere Integration Developer. Note that the service provider could be the sample RESTful back end service which is the servlet you used for scenario #2 or it could also be the mediation you created to wrap that service for scenario #1.
- Click Window > Show view > TCP/IP Monitor
Figure 60. Show TCP/IP Monitor view
- Right-click inside the TCP/IP Monitor view, then select Properties.
Figure 61. Showing the properties of the monitor
- Add a TCP/IP monitoring server and change the ports to match the environment on which you are testing the service.
Figure 62. Configuring the monitoring server
- With this configuration you should be able to monitor the traffic to your service. Send a request from any REST client you may have to the RESTful service. Note that you send the request to the port on which the RESTful service is deployed, not of the TCP/IP monitoring server itself. For example, if you have deployed the RESTful backend service on port 9090, then let the client send requests to that port rather than the port of the monitor you created which is 9083 as shown on the screenshot above. If you do not have a REST client ready, do not worry because you will see a tool that you can use for this purpose, in addition to some samples of code snippets for clients you may use to test your services, as well.
- As soon as you send a request to the service, you will find its contents in the TCP/IP Monitor view, where the request coming from the client is shown, and the response from the mediation module is available.
Figure 63. Displaying the content of requests and responses
As mentioned earlier in this section, you may use TCP/IP Monitor to monitor web services, as well, by following the same steps mentioned above.
cURL is a popular third-party open-source command line tool for transferring files and data to a URL which makes it suitable for testing the RESTful providers you have created. Below is a sample command that can be used to send requests to the example mediation flow you have created on WebSphere Enterprise Service Bus.
curl -H "Content-type: text/plain" -X POST -d "AccountNum=123" http://your_server_ip:your_server_port/RestIntegration_Medi ationModuleWeb/Export1
According to the logic of the sample RESTful service provided, the returned reply from
the service should be
Score=4000. You may like to monitor the request and reponse
exchanged as a result of this command between the cURL and your service using TCP/IP Monitor, as described in the previous section.
You can also use cURL to send SOAP requests to the web service provider you have created.
RESTClient is another third-party open-source Java application that can be used to test RESTful applications. The following steps show you how to use it to test RESTful services.
- Run RESTClient using the following command:
$ java –jar [path to RESTClient jar]
Figure 64. Running RESTClient tool
- Enter the URL of the RESTful service provider to be tested. For example, the URL of the mediation flow you created in scenario #1 on WebSphere Enterprise Service Bus.
Figure 65. Entering the URL of the RESTful service
- Change the HTTP method to POST.
Figure 66. Setting the HTTP method to POST
- Click the Body tab and type “AccountNum=123” which is the payload that will be sent to the RESTful service.
Figure 67. Entering the payload
- Press the Send button beside the URL field and observe the response from the RESTful service.
Figure 68. Viewing the response back
As mentioned with cURL, you may monitor the traffic send from RESTClient to the RESTful service provider using TCP/IP Monitor.
Web Service Explorer
Like TCP/IP Monitor, Web Service Explorer is a tool that is shipped with WebSphere Integration Developer and is part of the Eclipse platform. Web Service Explorer allows the developer to invoke web services given the WSDL of that service and its location. The following steps shows how can you test your web service providers using Web Service Explorer from within WebSphere Integration Developer.
- Right-click the WSDL file of the service to be tested. Select Web Services > Test With Web Service Explorer.
Figure 69. Running the Web Service Explorer
- If the endpoint of the Web service is not listed, add it using the Add link.
Figure 70. Listing the end-point of the Web service
- Click the operation that is intended to be invoked. For example, getAccountScore() of the sample web service provided or the mediation created for scenario #2. As shown in the image above.
- Select the endpoint and add the web service parameters that should be sent. For example, “123”, then click Go button.
Figure 71. Selecting the endpoint and passing the parameter
- You should see the result returned from the Web service provider.
Figure 72. The Response of the Web Service
Consuming RESTful service providers
One of the advantages you get by exposing RESTful services is that they can be consumed by a variety of client programming languages without running into interoperability issues. This is because RESTful interactions are based on HTTP protocol which is pretty much stable across different software product vendors. Following are code snippets written in JAVA .NET and PHP to invoke the same RESTful services you have created for scenario #1 and also the sample back end RESTful service you used for scenario #2.
A Java-based consumer could be a JavaServer Page (JSP) or a Servlet, for example. The following listing shows how to invoke the RESTful service you have exposed.
Listing 12. Calling the RESTful service from Java
//(1) URL url = new URL(the_URL_address_of_the_REST_provider); HttpURLConnection con = (HttpURLConnection)url.openConnection(); //(2) con.setRequestMethod("POST"); //(3) con.setRequestProperty("Content-Type", "text/plain"); //4 String content=”AccountNum=123” byte contentBytes=content.getBytes(); //5 OutputStream out = con.getOutputStream(); out.write(contentBytes); out.flush(); out.close(); //6 BufferedReader br =new BufferedReader(new InputStreamReader(con.getInputStream())); String result = br.readLine(); con.disconnect();
Step (1), opens a connection to the RESTful provider. Step (2) sets the HTTP method to POST which determines the operation to be carried out by the RESTful service. The HTTP headers are set in step (3). Step (4) prepares the request to be sent over the stream by converting the string into an array of bytes, i.e. binary. The request is sent in step (5). Step (6) read the returned response from the service.
Similarly, .NET consumers could be web based or a windows application. Being web based it could be classic ASP or modern ASP.NET.
Listing 13. Calling the RESTful service from C#
//(1) // url is the address of the REST provider HttpWebRequest myReq =(HttpWebRequest)WebRequest.Create((String) url ); //(2) myReq.Method = "POST"; String content=”AccountNum=123” byte contentdata = Encoding.UTF8.GetBytes(content); myReq.ContentLength = contentdata.Length ; myReq.ContentType = "text/plain ; myReq.Credentials = CredentialCache.DefaultCredentials; //(3) Stream strm = myReq.GetRequestStream(); strm.Write(contentdata,0,contentdata.Length); strm.Close(); //4 HttpWebResponse myres =( HttpWebResponse)myReq.GetResponse(); Stream recStream = myres.GetResponseStream(); StreamReader strRead = new StreamReader(recStream, Encoding.UTF8); string result = strRead.ReadToEnd(); strRead.Close(); myres.Close();
Step (1) opens a web request to the RESTful provider. Step (2) sets the HTTP request headers and prepares the payload to be sent in step (3) over the stream to the service. Step(4) reads the response from the service and releases held resources.
A consumer that is written in PHP would look like the following.
Listing 14. Calling the RESTful service from PHP
//(1) $properties = array( 'http'=>array( 'method'=>"POST" ,'header'=>"Content-Type: text/plain; charset= utf-8\r\n" ,"content"=>"AccountNum=123" ) ); //(2) $context = stream_context_create($properties); //(3) // $url is the address of the REST provider $result = file_get_contents($url, false, $context);
Step (1) sets the properties required to create the stream between the client and the server, which is done in step (2). Step (3) sends the request to the RESTful service and receives the returned result.
The authors would like to thank Greg Flurry who reviewed this article and gave valuable comments.
The responsibility of exposing your legacy applications as RESTful services can be delegated to the Enterprise Service Bus. RESTful services themselves can also be exposed differently using the Enterprise Service Bus. In this article, you have seen two scenarios; one of them exposes a back end web service as a RESTful service, and the other exposes a back end RESTful service as web service. The two scenarios were implemented on WebSphere Enterprise Service Bus, WebSphere Message Broker and WebSphere DataPower. You also learned how to test web service and RESTful interfaces. Finally, you have enjoyed the inherent interoperability from interacting RESTfully by implementing consumers in different programming languages that consume the same RESTful service.
- Overview of WebSphere Integration Developer HTTP Function selectors.
- Learn more about WebSphere Integration Developer's prepackaged HTTP data format transformations.
- Check out the WebSphere Message Broker information center.
- "Implementing REST services with WebSphere DataPower SOA Appliances" (developerWorks, Mar 2009) provides an introduction to Web 2.0 and REST with WebSphere DataPower SOA Appliances.
- View additional WebSphere DataPower Documentation.
- Check out the IBM WebSphere DataPower SOA Appliance handbook.
- View additional WebSphere DataPower Documentation.
- View the new Redbook on WebSphere DataPower SOA Appliances.
Get products and technologies
- Download IBM product evaluation versions or explore the online trials in the IBM SOA Sandbox and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.