Archive

Posts Tagged ‘soap’

Versioning SOAP Web Services using a Content Based Router

June 19, 2012 Leave a comment

Summary

In this blog post we discuss the evolution of a web service, and how multiple versions of it using the same endpoint can be handled by configuring Membrane ESB to act as a Content Based Router.

The Web Service

Suppose we have a very simple SOAP web service providing data about our customers. To keep it simple, we decided to just track the first and last name of each customer.

The web service is deployed and clients in the field are using it, for example to add new customers:

To add a customer, a client might send a message like this one:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:con="http://predic8.com/contactService/v11">
  <soapenv:Header/>
  <soapenv:Body>
    <con:addContact>
      <firstname>John</firstname>
      <lastname>Doe</lastname>
    </con:addContact>
  </soapenv:Body>
</soapenv:Envelope>

The structure used to describe customers was included in the WSDL:

...
  <xs:complexType name="addContact">
    <xs:sequence>
      <xs:element name="firstname" type="xs:string" minOccurs="0" />
      <xs:element name="lastname" type="xs:string" minOccurs="0" />
    </xs:sequence>
  </xs:complexType>
...

Modifying the Web Service

After the publication of the service, we noticed that we also wanted to track the email addresses of our customers.

We therefore changed the XML Schema used to describe customers to include a field “email”. A client using the new message format might now send:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:con="http://predic8.com/contactService/v20">
  <soapenv:Header/>
  <soapenv:Body>
    <con:addContact>
      <firstname>John</firstname>
      <lastname>Doe</lastname>
      <email>john@doe.local</email>
    </con:addContact>
  </soapenv:Body>
</soapenv:Envelope>

But now, we run into a problem: Some clients out there might still be using the old version of our service:

What do we do with them?

The Core of the Question

There are several possible answers to this question.

But firstly, there are also several “dimensions”, several design aspects to this question: When we added the “email” field, we basically created a new version of the web service:

  1. Did we change the published endpoint URL?
  2. Did we change the SOAP namespace URI?

Whether you answer (or should answer) “yes, yes”, “yes, no” or “no, yes” is up to you, and this blog post should help you decide that. (You should not answer “no, no”: At least in the long term, this creates trouble.)

In the rest of this blog post, we discuss “no, yes”.

Versioning with a Content Based Router

As both the old clients and the new clients are using the same endpoint URL, we need to distinguish between old and new requests. In our case, as we changed the namespace, we use the namespace URL to distinguish between old and new requests.

SOAP requests using the old namespace (http://predic8.com/contactService/v11) are sent to the old server, while requests usind the new namespace (http://predic8.com/contactService/v20) are sent to the new server.

Of course, the easiest way to realize the “old server” is to implement both the old and new server interface using updated and/or new methods internally.

Membrane Setup

We now setup Membrane ESB to act as the Content Based Router (CBR).

For this, we download the distribution from the website, and change conf/proxies.xml to:

<proxies xmlns="http://membrane-soa.org/schemas/proxies/v1/"
		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      	 xsi:schemaLocation="http://membrane-soa.org/schemas/proxies/v1/ http://membrane-soa.org/schemas/proxies/v1/proxies.xsd">

	<serviceProxy port="80">
		<switch>
			<case xPath="//*[namespace-uri()='http://predic8.com/contactService/v11']" url="http://localhost:8080/ContactService/v11" />
			<case xPath="//*[namespace-uri()='http://predic8.com/contactService/v20']" url="http://localhost:8080/ContactService/v20" />
		</switch>
	</serviceProxy>

</proxies>

VoilĂ !

(Starting Membrane with memrouter.bat will open port 80 and forward incoming requests to the specified URLs: We assume here that the server implementing both interfaces is running on localhost:8080 and the old (resp. new) interface is available on /ContactService/v11 (resp. /ContactService/v20).

A full working example of the versioned web service together with the CBR configuration can be found in examples/versioning/routing in the distribution archive of Membrane ESB.