REST (Representational State Transfer) is an important Web 2.0 technology that has become a popular alternative to other technologies that expose services, like SOAP-based Web services and Enterprise JavaBeans™ (EJB). Many prominent organizations provide REST APIs to their services; a common case is to expose a REST interface in front of an existing legacy system. This article looks at strict REST and provides a comprehensive example of how to use an IBM WebSphere DataPower XS40 or XI50 SOA Appliance to expose a REST interface in front of an existing Web service.
Web 2.0 champions a proliferation of new technologies; some of them are brand new and others are old but newly invigorated as they are applied to Web 2.0. The demand to utilize these new protocols and technologies to interact with existing enterprise systems is growing. DataPower is uniquely positioned to bridge Web 2.0 and SOA, as shown in Figure 1. DataPower can service Web 2.0 requests, such as an ATOM feed message or a REST invocation, and bridge to enterprise protocols, such as Web services, JMS, or even mainframe connectivity (for example, with IMS Connect). The case this article addresses is that of bridging REST client requests to a standard Web service backend system.
Figure 1. DataPower in Web 2.0 and SOA space
If you wish to follow along with the innstructions in this article, you will need:
- IBM WebSphere Application Server V6.1 or higher: The backend Web service provider used in the examples for this article is WebSphere Application Server V6.1. It should be very straightforward to use another application server to implement the demo service application from the WSDL, should you wish to do so. You can download a trial version of WebSphere Application Server.
- IBM WebSphere DataPower XI50 or XS40 V3.7 or higher: DataPower is the platform used here to transform and route REST requests to Web services.
- Curl: An open source command-line utility for sending files over HTTP. This article uses Curl to test REST HTTP methods. Download Curl.
In the context of this article, REST is not just XML and HTTP; there are rules to be followed in order to benefit from and adhere to the REST pattern. Below are some REST terms and explanations of how they are used in this article:
- Loose REST is domain data over HTTP without additional layers (such as SOAP) and without cookies. This is synonymous with XML/HTTP, and essentially a poor manâs SOAP. Loose REST utilizes only one HTTP method (POST) and follows an RPC style of communication.
- Strict REST offers a resource-based communication pattern. Network-addressable resources are used with a common set of verbs.
- Nouns simplify the access. All resources, or nouns, are network-addressable with a global URL. Resources have âhrefâ references to other related resources. The only way to address a resource is with a URL.
- Verbs simplify the actions. A common set of verbs are used to access all resources. The HTTP methods GET, PUT, POST, and DELETE map to retrieve, update, create, and delete (CRUD) functions. These are the only verbs that will be used.
- Representations simplify the format. REST provides multiple/alternate representations of each resource. A resource might be represented as XML, JSON, HTML, text, image, and so on. Instantiating representation from or to the resource is handled on the server. A client can pick its preferred representation via a URI parameter or the âAccept:â header.
Figure 2. REST triangle
The end goal is to have resources that have a uniform interface. All resources are addressable, there is a common verb vocabulary for resources, and there is flexible but understood representations of resources. This enables for radical simplification so that data can be easily consumed by any application.
A key benefit of strict REST is hypermedia links. Getting a collection of resources can return a summary plus links (URIs to each of the resources in the collection). The collection itself is a resource. The client can dynamically discover the URIs to the collectionâs resources with such links, instead of using a well-known URI for each resource in the collection. This enables the server to modify the URIs to the collectionâs resources without affecting the client.
Another key benefit is self-descriptive messages. The HTTP method and content-type are descriptive -- they describe the action and the resource representation -- unlike with SOAP, where they are ignored. This enables intermediaries to do more with the message without parsing the message contents.
These are the verbs used in each HTTP method for strict REST:
- GET: Fetches a resource from the server. This method is idempotent and safe.
- DELETE: Removes a resource from the server. This method is idempotent and non-safe.
- PUT: Creates a resource at the given URL. If a resource already exists at this URL, it is overwritten. This method is idempotent and non-safe.
- POST: Creates a resource in the given collection. The server can pick the resourceâs URL. Also for âprocess thisâ type communication. This method is non-idempotent and non-safe.
Strict REST is:
- A design pattern or architectural style
- Based on objects (resources) instead of methods (services)
- Session-less and stateless
- Cacheable
- GET method is safe and idempotent.
- PUT method invalidates cached content.
Strict REST is not:
- Removing SOAP envelopes from SOAP messages.
- Using query string instead of HTTP body.
- Using HTTP GET for all operations.
- Using HTTP POST for all operations.
- RPC.
- 1:1 facade to a service interface.
- A technology.
Figure 3 shows an overview of WebSphere DataPower exposing a strict REST interface that is backed by a SOAP-based Web service on the backend. The XML firewall accepts GET/PUT/POST/DELETE requests from the clients and then transforms the requests to corresponding SOAP requests, which are sent to the WS-Proxy. The WS-Proxy is optional; the SOAP requests could be sent directly to the backend. However, this is strongly discouraged as the configuration might require monitoring or security in the future. Thus, it is a best practice to include a WS-Proxy as part of a REST transformation configuration.
Figure 3. Overview of WebSphere DataPower exposing a strict REST interface
Also notice that the XML firewall is configured as a loopback firewall. This is necessary because the backend (which, in this case, is a WS-Proxy), only accepts requests that utilize the POST HTTP method. The HTTP method is available as a read-only system call. So, for example, if the client sends an HTTP DELETE, the DELETE method cannot be changed to POST. Thus, the backend of the XML firewall is not used, and explicit url-open or soap-calls from XSL are used to communicate with the WS-Proxy using HTTP POST.
The remainder of this article uses a common example to show how DataPower can expose a REST interface for a backend Web service. The sample DemoService Web service is a simple project organizer with which simple projects can be created, edited, and queried. The operations available for DemoService are shown in Table 1.
Table 1. DemoService operations
| Operation | Description |
|---|---|
| createProject | Creates a project on the server which consists of a project name, description, and identifier. The identifier is generated and returned in the response. |
| updateProject | Makes a change to a project. The project identifier, name, and description must be provided. |
| getProject | Fetches name and description of a project. The identifier of the project must be provided in the request. |
| listProjects | Returns all the projects. |
| deleteProject | Removes a project from the server. The identifier of the project must be provided in the request. |
The next sections show how to map these operations to a REST interface consisting of all the HTTP methods, GET, POST, PUT, and DELETE.
Download the sample DemoService application file included with this article, then follow these steps to install the DemoService.ear on WebSphere Application Server V6.1:
- From the administration console select Applications => Install New Application.
- Select Browse... and select the DemoService EAR, as shown in Figure 4.
- Select Next.
Figure 4. Install DemoService application
- Click on Step 3 on the left menu and select Finish.
- After the installation is complete click Save.
Follow these steps to manually create the WS-Proxy:
- From the DataPower control panel, select Web Service Proxy => Add.
- Enter
demo-service-proxyfor the name and select Create Web Service Proxy. - Upload the demoService.wsdl file (included in the download file), select off for WS-Policy References, and Next (Figure 5).
Figure 5. WS-Proxy configuration
- Select the + under Local Endpoint Handler and HTTP Front Side Handler.
- Enter
http-9080for the Name and9080for the Port Number and then Apply. - Back on the WS-Proxy configuration panel, select Add under Edit/Remove, and then Next at the bottom.
This completes the setup of the WS-Proxy. Save your configuration before continuing.
Import example DataPower configuration
To import the DataPower configuration to your XS40 or XI50 appliance:
- In the DataPower administration console select Administration => Configuration => Import Configuration.
- Click Browse... and select REST-DP-Export.zip (included in the download file), then select Next (Figure 6).
Figure 6. DataPower domain import
- Select Import.
If you inspect the XML firewallâs processing policy, the very first stylesheet that is executed is called "save-http-method.xsl," regardless of what type of message is received. The purpose of this stylesheet is to read the system variable that provides the HTTP method and save it for future use.
It is a best practice to setup processing rules for each HTTP method. The HTTP method can be accessed with the dp:http-request-method() system call. The stylesheet in Listing 1 captures the HTTP method and saves it to a context variable called var://context/projects/http-method.
Listing 1. save-http-method.xsl
<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:message><xsl:value-of select="dp:http-request-method()"/></xsl:message>
<dp:set-variable name="'var://context/projects/http-method'"
value="dp:http-request-method()" />
</xsl:template>
</xsl:stylesheet> |
Once the HTTP method is saved in a context variable, a call processing action can be used to select a processing rule that matches the HTTP method. The processing rule names correspond to the possible string values of var://context/projects/http-method: GET, PUT, POST, and DELETE. Figure 7 shows the call processing action and the four processing rules it invokes that correspond to the HTTP methods.
Figure 7. Call processing action
The next sections provide a description for each processing rule as well as a means to test each REST verb with Curl.
The next sections document the implementation of the REST XML firewall policy shown in Figure 7. This can be used as an exercise in DataPower REST development, as a working configuration to use as a starting point for other REST projects, or simply as a gauge for what transformation from REST to SOAP looks like with DataPower. These sections are presented by each DataPower processing rule: POST, PUT, GET, and DELETE. The same format is used to describe the implementation for each processing rule, which includes:
- Request payload: An example of the REST request payload.
- Response payload: An example of the REST response payload.
- Actions: Includes an image representing the processing rule with its processing actions. The numbering indicates the sequence of the processing actions.
- Code listings: Code listings for the stylesheets defined in the processing rules. Each listing is numbered according to the sequence numbers in the corresponding Actions figure.
- Curl command: An example Curl command to invoke the REST service with the corresponding HTTP method.
The POST processing rule corresponds to the createProject operation for the SOAP API.
- Request payload: project
Listing 2. POST request payload<q0:project xmlns:q0="http://soap.example.com/demoService/REST" > <q0:description>Research of ancient cultures</q0:description> <q0:owner>Alice</q0:owner> </q0:project>
- Response payload: None, but the location HTTP header should give the URL of the newly created resource.
- Actions:
Figure 8. POST processing rule
(1) rest-post-to-soap.xsl transform: This stylesheet transforms the REST project payload to the equivalent SOAP payload. Notice that the project description and owner are copied from the REST request. Also notice that the createProject SOAP action is saved in a context variable called var://context/rest/soap-action.
Listing 3. rest-post-to-soap.xsl<xsl:stylesheet xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 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="/"> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dem="http://soap.example.com/demoService/"> <soapenv:Header/> <soapenv:Body> <dem:createProjectRequest> <dem:newProject> <dem:description> <xsl:value-of select="//*[local-name()='description']"/> </dem:description> <dem:owner> <xsl:value-of select="//*[local-name()='owner']"/> </dem:owner> </dem:newProject> </dem:createProjectRequest> </soapenv:Body> </soapenv:Envelope> <dp:set-variable name="'var://context/rest/soap-action'" value="'http://soap.example.com/demoService/createProject'"/> </xsl:template> </xsl:stylesheet>
(2) call-demo-service.xsl transform: This stylesheet sends the SOAP payload with the SOAP action to the demoService Web service proxy. Notice how it uses the var://context/rest/soap-action variable saved previously. This stylesheet is reused in the subsequent processing rules.
Listing 4. call-demo-service.xsl<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://127.0.0.1:9080/DemoService /services/localDemoServiceSOAP',/,'',0,dp:variable('var://context /rest/soap-action'))"/> </xsl:template> </xsl:stylesheet>
(3) set-location-header.xsl transform: This stylesheet selects the ID from the SOAP response and sets the location HTTP header with the URL for the newly created resource.
Listing 5. set-location-header.xsl<xsl:stylesheet xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 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:variable name="id" select="//*[local-name()='id']/text()" /> <dp:set-http-response-header name="'Location'" value="concat('/projects/',$id)" /> </xsl:template> </xsl:stylesheet>
An example request is needed to test the POST REST method. This was provided in Listing 2. The payload was saved as RESTPostRequest.xml.
To send the request to DataPower, you can use this Curl command:
curl --data-binary @RESTPostRequest.xml http://DPHOST:8501/projects/2 -v
The âv flag enables you to see the headers returned from DataPower. There is no response payload, but pay special attention to the Location header, which returns the URL of the newly created project. For example, it returns /projects/3 when the third project is created.
The PUT processing rule corresponds to the updateProject operation for the SOAP API.
- Request payload: project
Listing 6. PUT request payload<q0:project xmlns:q0="http://soap.example.com/demoService/REST" > <q0:id>2</q0:id> <q0:description>Astronomy Project</q0:description> <q0:owner>Athena</q0:owner> </q0:project> - Response payload: none
- Actions:
Figure 9. Put processing rule
(4) rest-put-to-soap.xsl transform: This stylesheet transforms the REST project payload to the equivalent SOAP payload. Notice that the project ID, project description, and owner are copied from the REST request. Also notice that the updateProject SOAP action is saved in a context variable called rest/soap-action.
Listing 7. rest-put-to-soap.xsl<xsl:stylesheet xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 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="/"> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dem="http://soap.example.com/demoService/"> <soapenv:Header/> <soapenv:Body> <dem:updateProjectRequest> <dem:project> <dem:id> <xsl:value-of select="//*[local-name()='id']"/> </dem:id> <dem:description> <xsl:value-of select="//*[local-name()='description']"/> </dem:description> <dem:owner> <xsl:value-of select="//*[local-name()='owner']"/> </dem:owner> </dem:project> </dem:updateProjectRequest> </soapenv:Body> </soapenv:Envelope> <dp:set-variable name="'var://context/rest/soap-action'" value="'http://soap.example.com/demoService/updateProject'"/> </xsl:template> </xsl:stylesheet>
(5) call-demo-service.xsl transform: This is the same stylesheet used in Listing 4. This stylesheet sends the SOAP payload with the SOAP action to the demoService Web service proxy. Notice how it uses the rest/soap-action variable saved previously.
An example request is needed to test the PUT REST method. This was provided in Listing 6. The payload was saved as RESTPutRequest.xml.
To send the request to DataPower, you can use this Curl command:
curl -T RESTPutRequest.xml http://DPHOST:8501/projects/2
A blank response is normal and expected.
The GET processing rule corresponds to the getProject and listProject operations for the SOAP API. It can either retrieve a single project or a list of projects (collection).
- Request payload: None.
- Response payload: Project, ListProject
Listing 8. GET project response payload<q0:project xmlns:q0="http://soap.example.com/demoService/REST" > <q0:id>2</q0:id> <q0:description>Astronomy Project</q0:description> <q0:owner>Athena</q0:owner> </q0:project>
Listing 9. GET ListProject response payload<?xml version="1.0" encoding="UTF-8"?> <q0:projectList xmlns:q0="http://soap.example.com/demoService/REST"> <q0:project> <q0:id>3</q0:id> <q0:description>Research of ancient cultures</q0:description> <q0:owner>Athena</q0:owner> </q0:project> <q0:project> <q0:id>1</q0:id> <q0:description>Astronomy project</q0:description> <q0:owner>Alice</q0:owner> </q0:project> <q0:project> <q0:id>0</q0:id> <q0:description>Summer landscape project</q0:description> <q0:owner>Amber</q0:owner> </q0:project> </q0:projectList>
- An additional step for the GET method is to set the processing rule to
non-XML. The GET processing rule has no request payload so XML checking and
validation needs to be turned off. To do this go to the OBJECTS menu and select
XML Processing => Processing Rule => GET. Set Non-XML Processing to
on (Figure 10).
Figure 10. Disabling XML processing
- Actions:
Figure 11. GET processing rule
(6) rest-get-to-soap.xsl transform: This stylesheet constructs the SOAP request to get a project or list all projects. It corresponds to the getProject and listProject SOAP operations. Notice that the ID is retrieved from the URL and then either a listProjectRequest or getProjectRequest SOAP payload. Also notice that the SOAP action is saved in a context variable called rest/soap-action as either listProject or getProject.
Listing 10. rest-get-to-soap.xsl<xsl:stylesheet xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 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:variable name="url" select="dp:variable('var://service/URI')"/> <xsl:choose> <xsl:when test="$url = '/projects'"> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dem="http://soap.example.com/demoService/"> <soapenv:Header/> <soapenv:Body> <dem:listProjectsRequest></dem:listProjectsRequest> </soapenv:Body> </soapenv:Envelope> <dp:set-variable name="'var://context/rest/soap-action'" value="'http://soap.example.com/demoService/listProjects'"/> </xsl:when> <xsl:otherwise> <xsl:variable name="id" select="substring-after($url,'/projects/')"/> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dem="http://soap.example.com/demoService/"> <soapenv:Header/> <soapenv:Body> <dem:getProjectRequest> <dem:id><xsl:value-of select="$id"/></dem:id> </dem:getProjectRequest> </soapenv:Body> </soapenv:Envelope> <dp:set-variable name="'var://context/rest/soap-action'" value="'http://soap.example.com/demoService/getProject'"/> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>
(7) call-demo-service.xsl: As shown previously, the call-demo-service stylesheet is used again.
(8) rest-transform-get-response.xsl: Once the SOAP response is retrieved from the backend, it needs to be transformed into a REST payload. Notice how the project ID, description, and owner are retrieved from the input SOAP message and are used to construct the REST response. This process is repeated in the case that a project list is being returned.
Listing 11. rest-transform-get-response.xsl<xsl:stylesheet xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 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:variable name="url" select="dp:variable('var://service/URI')"/> <xsl:choose> <xsl:when test="$url = '/projects'"> <q0:projectList xmlns:q0="http://soap.example.com/demoService/REST"> <xsl:for-each select="//*[local-name()='project']"> <q0:project> <q0:id> <xsl:value-of select="*[local-name()='id']"/> </q0:id> <q0:description> <xsl:value-of select="*[local-name()='description']"/> </q0:description> <q0:owner> <xsl:value-of select="*[local-name()='owner']"/> </q0:owner> </q0:project> </xsl:for-each> </q0:projectList> </xsl:when> <xsl:otherwise> <q0:project xmlns:q0="http://soap.example.com/demoService/REST"> <q0:id> <xsl:value-of select="//*[local-name()='id']"/> </q0:id> <q0:description> <xsl:value-of select="//*[local-name()='description']"/> </q0:description> <q0:owner> <xsl:value-of select="//*[local-name()='owner']"/> </q0:owner> </q0:project> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>
To send a single GET request to DataPower, you can use this Curl command (the project ID is 2):
curl -G http://DPHOST:8501/projects/2
To send a GET request for a list of all projects, use this Curl command. Notice the project ID is omitted:
curl -G http://DPHOST:8501/projects
The DELETE processing rule corresponds to the removeProject operation for the SOAP API.
- Request payload: None.
- Response payload: None.
- As before, the DELETE processing rule has to be set to Non-XML Processing because it accepts a blank input. Follow the steps for the GET processing rule, shown earlier.
- Actions:
Figure 12. DELETE processing rule
(9) rest-delete-to-soap.xsl transform: This stylesheet constructs the SOAP payload to delete a project. It corresponds to the deleteProject SOAP operation. Notice that the project ID is retrieved from the URL and then used to construct the SOAP payload. Also notice the deleteProject SOAP action is saved in the rest/soap-action context variable.
Listing 12. rest-delete-to-soap.xsl<xsl:stylesheet xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 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:variable name="url" select="dp:variable('var://service/URI')"/> <xsl:variable name="id" select="substring-after($url,'/projects/')"/> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dem="http://soap.example.com/demoService/"> <soapenv:Header/> <soapenv:Body> <dem:deleteProjectRequest> <dem:id><xsl:value-of select="$id"/></dem:id> </dem:deleteProjectRequest> </soapenv:Body> </soapenv:Envelope> <dp:set-variable name="'var://context/rest/soap-action'" value="'http://soap.example.com/demoService/deleteProject'"/> </xsl:template> </xsl:stylesheet>
(10) call-demo-service.xsl transform: As seen before, the call-demo-service.xsl stylesheet is used yet again to send the SOAP payload to the backend.
To send a DELETE request to DataPower, use this command:
curl -X DELETE http://DPHOST:8501/projects/2
This article explained how IBM WebSphere DataPower fits in the Web 2.0 space, provided definitions around what we consider strict REST, described the recommended patterns to use for exposing REST with WebSphere DataPower, and included a comprehensive example with a DataPower domain export and the DemoService Web service backend application. You should now have a good understanding of what strict REST is, and how you can develop strict REST services on WebSphere DataPower so you can configure your own Web 2.0 appliance.
| Description | Name | Size | Download method |
|---|---|---|---|
| Code sample | 2009-2-18_REST-DP-Files.zip | 5.1 MB | HTTP |
Information about download methods
Learn
-
IBM Press: IBM WebSphere DataPower SOA Appliance Handbook
-
IBM Websphere DataPower SOA Appliances product information
-
IBM Websphere DataPower
SOA Appliances product support
-
REST Anti-Patterns
-
Architectural
Styles and the Design of Network-based Software Architectures: Representational State Transfer (REST)
-
IBM
developerWorks WebSphere DataPower zone
-
Introducing Project Zero, Part 2: RESTful applications in an SOA
Discuss

Robert R. Peterson is part of the Enablement Team under IBM Software Services for WebSphere. He travels the world implementing strategic proof of concept projects for future IBM software systems. He has published numerous technical books and papers, is a frequent conference speaker, and has filed several US Patents for enterprise systems. You can visit his website here.




