Versioning Web Service Parameters

Dare
makes a few comments
about one of my
previous posts
so I thought - in true blogsphere fashion - I'd follow-up in
a new post. First I'll mention a few more things about versioning web services,
then I'll get to Dare's comments.

Versioning web services can be very challenging depending on the results
you're trying to achieve. The primary decisions revolve around compatibility.
First scenario, the easy way out: no compatibility. If you choose this route, it
is highly recommended you implement a breaking change so your intentions are
clear. So, for the next version of your service, you change the namespace,
create a new endpoint address, and (re)deploy the clients for that service. When
I said the easy way out, I was referring to versioning ... obviously not
maintenance and deployments.

As you can imagine, there are a number of forces that can mandate a service
implement a breaking change. The most common of these is driven directly from
the business. The recommendation I make about using a single parameter for Web
Service operations is strictly for the scenarios when we're applying a
non-breaking change. We should always strive for compatible changes when we want
to avoid the maintenance and deployment headaches evidenced above. I think most
of this was understood in my previous posts, but I wanted to state it explicitly
just to be clear.

I think it's also important to make a distinction between different kinds of
Web Services, even if they're broad and sweeping. There is a considerable
difference between a service-oriented Web Service and one that is not
service-oriented. Perhaps my choice of GetTemp(
TempRequest ) was a poor one. Service-oriented operations are very
course-grained because they represent a business process. Because of this, the
service interface is not likely to change (unless the organization is going to
stop offering the service). However, the data pieces that service will require
could very possibly evolve over time. Therefore, it's important to be able to
version the service interface and the parameters of the operations
independently. If you agree at this point, then we need a way to identify what
version of the operation's inputs are being used. The only way to accomplish
this with multiple parameters is for one of the parameters, which has nothing to
do with the business logic of the operation, to contain version information.
With a single parameter, we can maintain a straightforward experience for the
client developer. Consider this message schema:

   <s:schema ... targetNamespace="urn:service">
    <s:element name="param" type="tns:UberParam" />
    <s:complexType name="UberParam">
      <s:sequence>
        <s:element name="param1" type="s:string" 
          minOccurs="0" />
        <s:element name="param2" type="s:string" 
          minOccurs="0" />
      </s:sequence>
      <s:attribute name="version" type="s:string" 
        use="required" fixed="1.1" />
    </s:complexType>
  </s:schema>

Just for completeness, the C# version of this parameter will look like
this.

   using System.Xml.Serialization;

  [XmlType( Namespace="urn:service" )]
  public class UberParam
  {
      public string param1;
      public string param2;
    
      [XmlAttribute()]
      [System.ComponentModel.DefaultValue( "1.1" )]
      public string version = "1.1";
  }

By providing a fixed value for the version of the data type, the service
developer has more metadata to work with and the client developer can focus on
only the job at hand.

   UberParam uber = new UberParam();
  uber.param1 = "value";
  uber.param2 = "value";
  MyService.Operation( uber );

Depending on the requirements, a Web Service acting more in the role of a
traditional API might not need this level flexibility. In these cases, I still
recommend a single parameter, but without the need of additional metadata, the
recommendation is less founded.

From Dare ...

Also the developer has to know how to manage interdependencies between
properties of the TemperatureRequest that are set if there are any that are
mutually exclusive, know which properties are required and whether to initialize
primitive values in the object to defaults without any help from the
API.

These issues are valid whether we have one parameter or multiple. The
developer is still required to know something about the API and its
requirements.

The other reason I like the former [multiple parameters] is that it
carries the impression that the XML Web Service end point is unchanging while
the latter [single parameter] does not.

As a client developer, I would find more comfort by feeling a
single-parameter service is constructed in a flexible enough way to withstand
the pressures of evolution.