I do a lot of work in distributed environments using service-oriented architectures. One of our biggest projects just launched, and at the time only had one client (Client A) consuming the web service. Now as the number of clients grows, the test is on to make sure we built the service as intended and any number of clients that need its functionality can use it without requiring major changes.
We’ve already run into a problem trying to make our second version of the web service backwards compatible, and unfortunately it is going to require the first client to update to the new WSDL. In the first version of the web service, one of our objects had a string property called AccountNumber. Now the Client B is integrating they require this existing object to support an array of AccountNumber. We had a couple of different options for how to approach this so that Client A was not affected:
- Add the AccountNumbers property with no other modifications.
- Add the AccountNumbers property and mark the original AccountNumber property with the Obsolete attribute.
- Make the AccountNumber setter point to the first index in the new AccountNumbers property.
Option 1 is the easiest, but for a new client offers the most confusion as they may not understand the difference between the two properties. The responsibility is also on the service now to determine which property was intended to be used or if both are supplied, which one takes precedence. Option 2 which I thought would be the best option, as that is the route to take when designing class libraries, actually surprised me. When marking a property obsolete, it is actually removed from the WSDL thus any client who provides that value is providing additional information that the WSDL doesn’t define. At this point, that was not going to work as well. Option 3 seemed it would also work good until I ran some unit tests and was having problems nullifying out the values. Once again the responsibility was up to the service to determine which value would be accepted if both happened to be supplied. What happens if the object was sent to the web service with the AccountNumber property set to a value and the 0th index in the AccountNumbers property set to null? The result depends on the order of serialization/de-serialization.
What option did we ultimately take out? We caved and dropped the AccountNumber property and implemented the new AccountNumbers property, requiring our client to update their version of the WSDL so that they could comply with our service.
What defines a web service as a backwards compatible web service? This happens when:
- new methods are added to the service
- restrictions are removed (access restrictions, mandatory values are now optional, etc.)
- optional attributes and properties are added
- attributes are changed but their type is compatible with the previous type (number to string)
Herein lies the complication with building web services and making sure that you design so that further down the road you don’t require all of your existing clients to change to adapt to your updates. Fortunately for us, there was only one existing client, so this change is much more possible.