RESTful Services with Oracle Service Bus

 Recently I was asked about REST (see http://en.wikipedia.org/wiki/Representational_State_Transfer)
support in Oracle Service Bus. OSB 10gR3 has full support for REST and
implementing a REST approach in a proxy service is very simple. In this
example, we will create a proxy service that provides a REST interface to a
product catalog.

Why use OSB for REST?

Using the Oracle Service Bus to provide an interface as
simple as REST may seem odd at first. There are several good reasons for this
approach though.

  1. You automatically get all of the monitoring, reporting, security and more provided
    by OSB for your RESTful services

  2. You keep the benefits of mediation. For example, of our company in this example
    purchased another company that provided different products, you could use the
    OSB to act as a fa├žade over both product catalogs while providing a single,
    unchanged REST interface.

  3. You
    can REST-ify existing, non-service enabled assets like EJBs

The Products Proxy Service

Let's get started. First we will create a new OSB
Configuration Project to house our REST services. I named the configuration
project RESTConfig in the sample source code. You can download
the sample source code here.

Inside of the RESTConfig project I then
created a standard OSB project named SimpleREST. Once the OSB
project was created, I was ready to start creating my REST project.

Next I created a proxy service named Products.
I used the default endpoint URI of SimpleREST/Products but in a
production environment you'll most likely want to customize that. Be sure to
define your proxy service as an Any XML Service so you can accept
and return XML of any flavor.

Now it is time to create our message flow. Here is where
it gets interesting. One of the fundamental concepts in REST is the use of the
native HTTP methods to allow the service consumer to express their intent. The
specific HTTP methods that we are interested in are: GET, POST, PUT, HEAD,
OPTIONS and DELETE. In this example I don't make use of the TRACE method.
However, you will be able to add that to your projects easily after reading
this.

The handling of each of those methods is different, so we
begin our message flow with a Conditional Branch node (see figure 1). I added a
branch for each of the methods I was interested in. In the Conditional Branch
node I set the XPath field to ./ctx:transport/ctx:request/http:http-method/text()
and theIn Variable field to inbound. This is the equivalent to the XPath
expression $inbound/ctx:transport/ctx:request/http:http-method/text().
The text() operation at the end is important because I
want to deal with the method in its plain text form and not as an XML
expression.


image001.jpg

Figure 1 Standard OSB REST Pattern

When adding the branches it is important to enclose the
contents of the Value field in single quotes (Figure 2) to denote it is a
string value. If you forget this, you will get an error about an unbound XML
node when you run the proxy service because OSB will treat the contents of the
Value field as a variable instead of a string literal.

image002.jpg

Figure 2 Don't forget the quotes!

For each branch, add a pipeline pair and name it
appropriately, as shown in figure 1. Before we fill in the GET Pipeline with
the necessary logic, let's take a moment to decide how we want the HTTP GET method
to be handled. Ideally, we want to be able to point a web browser or other REST
service consumer to a URL like: http://localhost:7001/SimpleREST/Products/id=# to
retrieve a product representation by its ID. Since the proxy service is
listening at http://localhost:7001/SimpleREST/Products,
the remainder of the URL (i.e. the id=#) will be accessible in the message
flow as the relative-URI part of the $inbound variable.

The GET Method

Now that we know what the URL should look like for a GET,
we can fill in the logic. In the GET Pipeline (Figure 3) we will add two Assign
actions. The first Assign action will get the first part of the relative URL
(i.e. the id part). We won't do anything
with this part in this example, but you can use this technique to ensure that
the URL used had the correct format. The expression to use in the first Assign
statement is as follows:

fn:tokenize(data($inbound/ctx:transport/ctx:request/http:relative-URI),
'=')[1]

This expression will take the relative-URL value and
tokenize it using the '=' character, returning the first token. So if the
relative-URI is "id=27" this expression will return the "id" string. Why XPath
counts from 1 instead of 0 I don't know. Set the Variable field to attr and you are
done with the first Assign statement.

The second Assign statement is very similar to the first,
except we are retrieving the second part of the relative-URI. Its expression is
as follows:

fn:tokenize(data($inbound/ctx:transport/ctx:request/http:relative-URI),
'=')[2]

Set the Variable field to productID. In the sample code I include
a Log statement to output the contents of these variables to the console

image003.jpg

Figure 3 The GET Pipeline

In the Response Pipeline we will construct our response
message for the GET. We will just mock up a product document for this tutorial.
The following code snippet (which you will put into the Expression field
of the Replace action) shows the value that the Replace action will put into
the $body
variable, which is then returned to the caller.

<Product>
<ID>{$productID}</ID>
<Name>Foobar</Name>
<Price>19.99</Price>
</Product>

Listing 1 Constructing the response document

Set the XPath field to just a period (.) and be
sure to select the Replace Node Contents  radio button. If you deploy
the project you can test it using your web browser. Assuming your OSB server is
running on the default port 7001, you can use the following URL:

http://localhost:7001/SimpleREST/Products/id=2

Your web browser should show you the following:

<Product>
<ID>2</ID>
<Name>Foobar</Name>
<Price>19.99</Price>
</Product>

Note: Capitalization counts even with REST

Alternatively, you can use the OSB Test Console instead of
a web browser. I recommend using the Test Console (Figure 4) because it gives
you more control over the service call and visibility into the message flow. To
test the GET method, right-click on the Products.proxy file in the
Workshop IDE and select Debug As -> Debug on Server.... When the Test
Console appears, click on the down-arrow icon in the Transport section. This
will allow you to set the relative-URI and http-method fields directly.

image004.jpg

Figure 4 The Transport section of the Test Console

When you are happy with your settings, press the Execute
button to run the test. The Test Console (Figure 5) will return the results and
provide you with the response metadata and the invocation trace, which is
useful when debugging your proxy services.

image005.jpg

Figure 5 The Test Console response

Now that we have the GET branch taken care of. Let's take
a quick look at the other HTTP methods that we are supporting.

The POST Method

The HTTP POST method is traditionally used with REST to
create new entities. The message content that is POSTed can be in XML format, or
in the format used by HTML forms, which is still the most common mechanism for
submitting data to a web site in use today. However,, I highly recommend that
you keep your information in XML format instead of the HTML Form format simply
because the HTML Form only  supports the GET and POST verbs, whereas with REST
we also want to use the other verbs, like PUT and DELETE.

The POST Pipeline shows how to handle the POST method. It's
pretty simple in that it extracts the specific information it wants from the
$body and then creates and returns an XML representation, simulating the
creation of a product. You can use the OSB Test Console to test this method by
setting the http-method field to post and then typing in the payload as
follows:

<Product>
<Name>Widget</Name>
<Price>99.99</Price>
</Product>

The two Assign statements in the POST Pipeline simply
extract the name and price information and return a representation of the new
product, with a hard-coded ID of 777

The PUT Method

The PUT method is used to update an entity. It operates
very much like the POST method does, except this method will expect to see the
ID in the submitted product representation. You can test this operation in
pretty much the same way that you tested the POST, just change the http-method
to PUT and use the following as your payload:

<Product>
<ID>999</ID>
<Name>Widget</Name>
<Price>99.99</Price>
</Product>

Here we will add a little error checking to ensure that
the ID for the product has been specified. The If-Then action (Figure 6) uses
the expression: exists($body/Product/ID) to test
for the presence of the ID element.

image006.jpg

Figure 6 The PUT Pipeline

If the ID element is defined, we then use a single Assign
statement to create our entire response document as follows:

<Product>
<ID>{$body/Product/ID/text()}</ID>
   <Name>{$body/Product/Name/text()}</Name>
   <Price>{$body/Product/Price/text()}</Price>
</Product>

If the ID element is missing from the $body, then we throw
an error to alert the service consumer of the problem. In the response pipeline
we simply set $body
to the value of $responseDoc, what was created in our Assign statement.

The HEAD Method

The HEAD method is used to return metadata about a
representation to the caller. It's called the HEAD method because the metadata
is returned in the HTTP headers. This metadata can be anything you want it to
be, but a good place to start is the standard HTTP headers used by the
Inbound-Response to the Inbound-Request. Figure 6 shows the message flow for
HEAD Pipeline (Figure 7). All we do is populate the data of a single Transport
Header action in the response pipeline.

image007.jpg

Figure 7 Implementing the HEAD method

Its up to you and your specific needs to define which
headers you want to send back for the HEAD method, but I recommend sending at
least the HTTP Content-Type header with a value along the lines of 'text/xml; charset=utf-8'.
This will help the HTTP clients know how to parse the text that is returned.
Setting the Connection header to 'keep-alive' is also generally a good idea.

The OPTIONS Method

Finally, the OPTIONS method is used to convey to the
caller which HTTP methods are appropriate for the Products entity. In this
case, all we need to do is to specify a Transport Header for the outbound
response (see figure 8).

image008.jpg

Figure 8 Implementing the OPTIONS Pipeline

Configure the Transport Header as shown in figure 9.

image009.jpg

Figure 9 Transport Header Settings

The expression for the header is 'GET, HEAD, PUT, DELETE, OPTIONS'. It
may not be necessary to add the OPTIONS clause, since you have to call it in order to get
the response in the first place, but I show it for completeness. That covers
the basics of using OSB to implement RESTful service patterns. As you can see,
it's quick and simple to do. Using this technique you can wrap any
functionality in your enterprise using a REST service interface.

The DELETE Method

The DELETE method is very straight forward. It expects to
have a product ID specified on the URI and it simply deletes the product with
that ID. Due to its trivial nature, it is not implemented in the sample code.

Calling RESTful Services from OSB

In addition to providing a REST interface, OSB can also
invoke REST services. For this part of the exercise we will provide a standard
SOAP interface to OSB. OSB will then take those SOAP calls and invoke the REST
services accordingly. The WSDL for our SOAP interface defines the following
operations:

getProductDetail(productID)
createProduct(name)
updateProduct(productID)
deleteProduct(productID)

Each of these operations will be performed by the REST
services we created earlier in this tutorial.

We begin by creating a proxy service named CallREST based
on the Products.wsdl file (in the WSDL folder of the SimpleREST project). Since
the WSDL defines several SOAP operations, we start the message flow with an
Operational Branch node, and create branches for each of the operations we want
to handle. Once that is done, add a Pipeline Pair to the getProductDetail
branch, as show in Figure 10.

image010.jpg

Figure 10 The basic structure for the CallREST message flow

The getProduct Pipeline consists of a single Stage
node, as shown in Figure 11. The initial Assign statement is used to extract
the product ID from the request document and store it in the $productID
variable. The next node is a Service Callout

image011.jpg

Figure 11 The getProduct Pipeline stage

The Service Callout (Figure 12) is where most of the work
is done. To configure the Service Callout, be sure to check the Configure
Payload Document radio button since REST does not use a SOAP format. Set the Request
Variable
field to requestBodyDocument
and the Response Variable field to responseBodyDocument. That's all you need to do for the Service Callout action.

image012.jpg

Figure 12 Service Callout contents

The first action is a Transport Header. Configuring this
action is simple. Set the Direction field to Outbound Request.
Also, be sure to check the Pass all Headers checkbox.

Immediately after the Transport Header action are two
Insert actions. The first insert action (Figure 13) is used to specify the HTTP
GET method. Configure it as shown in Figure 13

image013.jpg

Figure 13 Specifying the HTTP GET method

The second and last Insert action (Figure 14) in the
request pipeline shows how to specify the relative-URI of the request. The expression:
<http:relative-URI>id={$productID}</http:relative-URI>
is used to create the value of the relative-URI of the outbound request
variable.

image014.jpg

Figure 14 Specifying the Relative-URI of the request

At this point our request of the REST service is properly
formatted. Once the REST service is invoked, the response will be returned to
our message flow in the responseBodyDocument
variable. In the Response Action pipeline of the service callout, we add a
single Replace action (see Figure 15) to take the response document from the
REST service and format it to meet the needs of our SOAP operation.

image015.jpg

Figure 15 Formatting the <body> that our operation returns

The remaining branches follow a similar pattern so there
is no need to document them here. If you want to see the sample code for this
blog entry, you can download it from here:
Download Source

Conclusion

As you can see from this sample, it is very easy to use
Oracle Service Bus to both call existing REST services, and to have OSB provide
a REST interface to existing SOAP services. The benefit of REST is the
simplicity of the interface design. By marrying OSB and REST, you get the
simplicity of REST, while maintaining the ability to define SLA's on each
service or operation, maintain visibility over these operations using OSBs
built in monitoring and reporting, and still retaining the necessary agility by
being able to quickly alter the OSB message flows and aggregating/orchestrating,
multiple services in the "backend" without the implicit knowledge of the
service consumer.

Comments:

Hi Jeff: I am working in the implementation of native REST Web Services for Oracle 11g using Java inside the database: http://docs.google.com/EmbedSlideshow?docid=ddgw7sjp_475ccwb5p9n I would like to test the idea of Native Data Services to see if it fits with OSB architecture. If you want We can exchange some samples as prof of concepts. Best regards, Marcelo.

Posted by Marcelo Ochoa on June 04, 2009 at 06:32 AM PDT #

Great website! I add this site to my bookmarks! Thanks for webmaster!

Posted by Wanda on July 10, 2009 at 09:40 PM PDT #

How does REST handle security? What is OSB support for secured REST invocation? For example, if you want to dictate who can post or put, how is handled?

Posted by Stanley Guan on July 31, 2009 at 05:34 AM PDT #

Hi, Can some one give me an idea as to how I can expose BPEL process (Deployed as webservice) as Rest Interface. BPEL process uses xml as input and responds with xml as output thanks

Posted by Raghu on September 20, 2009 at 08:51 AM PDT #

Do you have an example of BPEL process exposed as Rest Service Using OSB

Posted by Raghu on September 24, 2009 at 06:45 AM PDT #

Hi, I created OSB services as directed above. my OSB structure looks like: PROJECTS |___LN |____restws |______restProxy |______restBusiness In OSB Test Tool, it works fine for all method-calls. But when i try to call it through browser it returns me 404 Not Found error. URL i m requesting in browser is : http://:port>/restws/restProxy Please guide where i m going wrong

Posted by Megha on September 25, 2009 at 05:15 PM PDT #

We have formed query string and relative uri from xml request in proxy example QS: sessionid=123456&opid=ajoy&port=sim&serviceid=delete&msisdn=20161 example relative uri : gui. relative uri can be either gui or selfcare. Now the web application we are invoking with this query string and relative uri require basic authetication. If relative uri is gui we have to set one set of user name and password and if selfcare we have to set another set of userid and password. Please suggest how to do it.

Posted by Ajoy on November 08, 2009 at 02:13 PM PST #

Great Article. Do you have an example of exposing a SOAP/WSDL service in the Bus as this REST service example? Thanks, Jay

Posted by Jay Blanton on May 20, 2010 at 05:16 AM PDT #

I'm not sure i quite understand your question. If you want to take an exisitng SOAP service and expose it as a REST service, you would use this sampe to create a REST interface and then connect to the SOAP service by creating either a service callout or a route. If you are looking for examples for how to create a SOAP service using OSB, then OTN has some samples that I have written up. You can find the samples under the OSB heading at https://soasamples.samplecode.oracle.com/#osb I hopoe this helps. Thanks Jay.

Posted by Jeff Davies on May 20, 2010 at 05:38 AM PDT #

Thanks for the answer and sorry for not being very clear. This article is about creating a REST Service and then creating a sibling version that takes a WSDL/SOAP and converts it to REST. Is that correct? Yes, I want to try and do the opposite by creating a WSDL/SOAP service initial and a REST version that calls the WSDL/SOAP by wrapping it in a SOAP message. So I would assume I do the opposite. That way I would take REST requests and map the HTTP Method and message to the WSDL/SOAP operation and then wrap the XML (that comes via REST) and put it into a SOAP Envelope. It's just that the message we will be exposing through the bus will probably be code generated "Contract First", but I want the business service layer exposed as REST as well for our presentation layer to invoke via REST instead of WSDL/SOAP. This article was extremely helpful.

Posted by Jay Blanton on May 21, 2010 at 07:25 AM PDT #

Is it possible to create a proxy or business service from a restful web service that runs outside of OSB?

Posted by Andy on September 28, 2010 at 03:25 AM PDT #

When you are connecting to an external REST service you create a business service that knows how to connect to the REST service. The article shows how to create a RESTful proxy service. The real power in the OSB mediation layer is that you can create a proxy service using any variety of interfaces and transports that, in turn, wrap the business services that may also be implemented with a wide variety of interfaces and transports. For example, you may create a single proxy service that publishes a REST interface and makes use of several business services in the backend that may be any mixture of SOAP, EJB, FTP, EMAIL or any of the other protocols supported by OSB. The inverse is true also.

Posted by jeff.x.davies on September 28, 2010 at 04:06 AM PDT #

Hello Jeff,
I need to generate a SOAP message which is encapsulated in a MIME multipart/related message. I managed to generate the SOAP message. I created a business service of type Any SOAP type and a Proxy to call the same, added the soap header and the body in the proxy and call the business service.
However i am not sure how to enclose this message in a MIME message. Should i create another service of type Messaging Service and try sending it? Any pointers much appreciated.
Following is the format i need to send it to the third party site.

MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="MIME-Boundary"
content-transfer-encoding: 7bit

--MIME-Boundary
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: 8bit

>SOAP ENVELOPE<
--MIME-Boundary__

Posted by guest on September 15, 2011 at 08:58 PM PDT #

Hello Jeff:

What should be done if the RESTFUL webservice is on a different server?
I couldn't find another way of getting the hostname:port other than hard coding it in the message flow.

Any suggestions?

Posted by John on November 30, 2011 at 09:12 AM PST #

I am not able to download the source code you mentioned at the beginning of the blog post. Link disabled?

And yes, very helpful post by the way.

Posted by REST on December 13, 2011 at 11:18 PM PST #

Hi Jeff,
We are using Oracle Service Bus 11G. Thank you for sharing lot of articles. I have created restful proxy service which will take http query input from the consumer through a browser. This restful proxy will be communicating with service developed by using wsdl/soap (webservices). I assume proxy needs to prepare body in xml before it routes it routes to a business ervice. I am wondering whether we have any tools to prepare xml. Could you forward any articles or examples to resolve this issue.

Thanks

Posted by guest on February 04, 2012 at 11:37 PM PST #

Hello Jeff,
I need to call twitter restful services using OSB and I am stuck on how I would go about starting it. If you could point me in the right direction or give me hints/information about what to use in order to accomplish for example POST twitter api rest call in order to tweet a message using OSB. Anything will help and your time will be much appreciated!

Thank you,
Albaraa Al-Hiyari

Posted by Albaraa on May 24, 2012 at 03:17 PM PDT #

It should be fairly straightforward. I'd open up my web browser with the form that allows me to post to twitter, and then make the appropriate changes in the OSB project. A POST is a POST as far as HTML is concerned.

Best of luck!

Posted by Jeff on May 25, 2012 at 02:55 PM PDT #

Looks like the original sopurce code I posted was incomplete (missing some key folders). I have updated it with the complete source now.

Posted by Jeff on June 19, 2012 at 11:14 AM PDT #

Hi,

great article, I downloaded the source (simplerest_source.zip) and imported into OSB 1031 but it contains only folders proxy/xquery/xsd.
I didn't find any reference to resources mentioned in the above "Calling RESTful Services from OSB", I mean the proxy service named CallREST and the Products.wsdl file.

I'm working on an OSB project where I need to call a REST web service with a business service from a proxy service.

May I ask you to publish the entire OSB project you describe in the above article ?

Thanks and regards
Patrizio Ferlito

Posted by Patrizio Ferlito on October 03, 2012 at 05:17 AM PDT #

Hi,

This is manohar,

can u check out the below url and let me know how to send http post request .. Here I am using osb11g

https://sites.google.com/a/limos.com/web-api/search-api-version-2/the-search-resource

thank in advance,

Posted by guest on October 16, 2012 at 02:12 AM PDT #

Hi,

Thanks for sharing such wonderful article...
Although this query is not related to this article but would want to know your opinion on one design query:
If we have to build a middleware system that requires to handle high volume say of 1.5 Lac requests within 10 mins, then what would be a better option.
1. OSB alone can handle this high volume
2. SOA Suite(bpel,mediator)
3. Combination of SOA and OSB.

Regards,
Saurabh

Posted by saurabh on February 09, 2013 at 09:16 AM PST #

@saurabh
I'm not sure what an Lac is but for the sake of discussion I will assume you system needs to process 1.5 million requests every 10 minutes. You don't mention what type of processing you will do on those messages though, and that's the critical bit of information needed for selecting the proper tool.

We don't have the time or space to get into the details of your project, but I can provide you with some general guidance on using service bus and the rest of the SOA Suite together. 1.5M messages every 10 minutes comes to 2500 messages per second, something service bus can do with ease. If you are simply providing access to one or more other services in your back office, service bus alone may very well be all you need. In this scenario, you are using service bus only to mediate between service providers and consumers.

However, if you need to do significant work on the messages, I would then opt to use service bus as a proxy/facade over the rest of SOA Suite. Service bus would receive a message, and possibly route it to the appropriate SOA SUite applications for further processing.

Remember that service bus operates as a stateless process engine. If you need stateful processing, that's where SOA Suite (specifically the BPEL component of SOA Suite) really shines. Also, SOA SUite has a components for business rules, human workflow, B2B and more. Service Bus and SOA Suite combined allow you to handle pretty much any business challenges.

- Jeff

Posted by jeff davies on February 11, 2013 at 09:17 AM PST #

Thanks a lot jeff for your valuable input, my requirement is somewhat like this: build a middleware system comprising of approximately 25 proxy services, 15 business services, 30+ xqueries,10 java callouts,5 database jca callouts. And should be able to handle around 1 Million requests/response coming and going out of osb restful proxy service within 10-15 mins during peak hours. Can OSB alone handle this or will require SOA Suite in combination to perform well?

Posted by saurab on February 12, 2013 at 09:43 AM PST #

I installed soa suite 11gr1. I want to change service to REST on Weblogic but I have litle known about osb. I not yet understand to configure flow message on osb.

Posted by Rafael on July 02, 2013 at 10:48 AM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

A site for SOA thought and discussion.

Search

Archives
« July 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
       
Today