BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News REST and versioning

REST and versioning

This item in japanese

Bookmarks

Recently Ganesh Prasad has been thinking about that thorniest of subjects:versioning of services within a REST-based architecture. Ganesh has an example to illustrate:

Assume that there is a Resource identified by "/customers/1234". Updating the state of this customer requires a PUT. [But how can] REST handle a change to the business logic implied by the PUT[?]

Since there's no way to change the operation used (e.g., specifying PUTv2) to indicate that the service (business logic) has changed, one option would be to change the URL used for PUT, whilst at the same time maintaining the original identity, e.g., as Ganesh shows:

PUT /customers/v2/1234 and this is different from the identity of the customer, which remains at /customers/1234

This is similar to an anti-pattern that Peter Williams discussed a couple of years back and others before even that. As Peter said in 2008:

I really hate this approach as it implies that an account in one version of the API is really a different resource than the account in a different version of the API. It also forces clients into a nasty choice, either support multiple versions of the API simultaneously or break one of the core constrains of REST. For example, say a client exists for the v1 API that saves references (URIs that include the version indicator) to accounts. Some time later the client is updated to support the new version of the API. In this situation the The client can support both versions of the API simultaneously because all the previously stored URIs point at the old version of the API or it has to mung all the URIs it has stored to the point at the new API. Munging all the URIS breaks the HATEOAS constraint of REST and supporting multiple versions of the API is a maintenance nightmare.

In Peter's approach to versioning he suggests a combination of custom media types and content negotiation (for those backwardly incompatible changes that are sure to occur eventually).

This approach does lead to media types being created, but media types are cheap so we can — and should — have as many as we need. Used properly, content negotiation can be used to solve the problems related to versioning a REST/HTTP web service interface.

But back to Ganesh and the initial approach to modifying the URL, which he also disagrees with.

First of all, it's a mistake to think there are only two places where the version of business logic can be exposed - the Verb and the Resource. The data submitted is an implicit third [...]. But this example only makes me question the whole basis for versioning.

He goes on to question the need for versioning in REST and SOA, asking the questions what is versioning in the first place and why is it needed?

I would say service versioning is a mechanism that allows us to simultaneously maintain two or more sets of business logic in a consumer-visible way.

He questions why this has to be visible to customers in the first place. For instance, if a service can differentiate between types of customer then surely it can apply different business logic internally and opaquely to the invoker (client/customer)? He then posits a further question: Why do we need to maintain two or more sets of business logic simultaneously?

The interesting (and circular) answer is often that business logic happens to be consumer-visible, hence a new version of business logic also needs to be distinguished from the old in a consumer-visible way. This is often stated as the need to support legacy consumers, i.e., consumers dependent in some way upon the previous version of business logic.

The need to support legacy is to ensure that existing contracts and SLAs are not broken when services are (silently) upgraded. This then leads Ganesh to question whether or not the answer to the versioning problem is found not in the use of explicit versions but in abstracting specific details, i.e., perhaps service contracts are too specific and hence too brittle when changes occur. (Similar train of thought to the old loose coupling versus tight coupling that has been one of the principles behind SOA.)

Using an example, Ganesh then goes on to discuss how this approach may be used to tackle the versioning problem. In the example his fictional developer makes a change to a service's business logic after there are existing customers.

The first question is, can this new business logic be applied to all customers, or do we need to keep track of "old" customers and keep applying the old business logic to them? If we can "upgrade" all customers to the new business logic, there is, of course, no problem at all. The interface remains the same. The client application POSTs data to the same URI, and they are redirected in the same way to the location of the newly-created [...] Resource. The business logic applied is all new, but customers don't see the change in their interface [...]

But of course it may be impossible to do this and hence require the maintenance of multiple different instances of the business logic. Ganesh then enumerates the reasons why that may occur:

  • "the data that the client app needs to submit has changed, so the change is unavoidably visible to the customer and has to be communicated as a new and distinct contract."
  • "there is another business reason to tell two types of customers apart, perhaps to reward longstanding customers with better rates, and this difference between customers is not obvious from the data they submit."
  • "the client app somehow "knows" the behaviour of the old version and is dependent on it. In this case, we need a new version just to keep legacy clients from breaking.

According to Ganesh, the third option is artificial and means breaking loose coupling by causing explicit dependencies to occur between customer and backend implementation.

In contrast, the first and second reasons provide their own resolution. If the type of data submitted by the client changes, that is itself a way to distinguish new clients from old ones and apply different business logic to them. In other words, we only need to tell newer customers about the change in the data they need to POST. Older customers don't need to do a thing. Also, if we can somehow derive that the customer is an existing one, even if this is not explicit in the data submitted, we can still apply different business logic transparently.

He concludes with the assertion that ...

Service versions are not really an interface detail. They're an implementation detail that often leak into the interface.

The service versioning problem is something that crops up time and again in a number of areas, not just REST. However, Ganesh believes that REST offers a better, more natural solution to the problem.

Rate this Article

Adoption
Style

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Community comments

  • Mime types

    by James Watson,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    The idea of using types for versioning is one that would not have occurred to me in the past because I wasn't really aware that I could/should create custom mime types. Maybe I'm just thick but I think it might have something to do with an aspect of the REST community that I think holds it back: a lot of people doing REST assume that everything should and will be public (see tools.ietf.org/html/rfc4288#section-3.2). The reality is that most services will never be exposed publicly nor should they be. There is no value in registering mime-types for these services.

    The problem about using types (which I think might really work well, BTW) for versioning is that the client needs to be a fairly sophisticated user of HTTP. In a recent project where I successfully argued for and implemented a REST-leaning set of services, I had a lot of trouble just getting our 'highly skilled consultants' to figure out how to make a HTTP call that wasn't implemented by a SOAP toolkit. I might have been able to get then using special accept headers etc. but I would have been challenged on it.

    I think that the REST community needs to be careful about dismissing real problems. When you suggest the need for versioning is created by design mistakes, well... Maybe but so what? Is the suggestion that people should never make any mistakes? That's not a realistic strategy. In general, any strategy that requires flawless execution is doomed to fail. You must allow for contingencies to succeed.

  • In-band vs. out-of-band

    by Bill Burke,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    I think the discussion here immediately got off track by talking about two different URL schemes:

    /customer/1234
    /customer/v2/1234

    Specifically, Peter's comment of "I really hate this approach as it implies that an account in one version of the API is really a different resource than the account in a different version of the API". URL scheme is an implementation detail that should be hidden from the client.

    IMO, designing REST applications is about using as little of out-of-band information as possible and relying as much as possible on in-band information.

    1) Publish very few URLs and instead require clients to follow in-band links to interact with the application
    2) Publish alternative links so that clients can take advantage of refactored and new functionality and features
    2) Define backward and forward compatible media types. i.e. in XML schema, be liberal with XmlAnys so that a schema can be easily extended with additional information. Make new elements and attributes optional in future versions.
    3) Versioned media type declarations are another tool that can be used dependending on the situation. i.e. application/customer;version=1

    The key is for both the client and server to be sensitive to what they are receiving. Examine the requests/responses to see exactly what the client or server is telling you what it wants to do. This is so subtly different than what we're used to in traditional distributed computing.

  • Re: Mime types

    by Shimon Amit,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    Nicely put. Design for your customers first.

    I have profiled a number of SaaS billing providers, and found that during their sales pitch, a number of them put strong emphasis on how straight forward their API was, and that they were willing to discuss it with us in detail. Why did they do that? Apparently some prospects would walk away if they thought the API was too complex. Yes, because of the API.

    REST in its purest form puts a heavier onus on your customers' shoulders compared to SOAP. Client software has to be smarter, with adaptive capabilities built in. (That's at least until the folks at Restfulie bang out more awesomeness with their client and server REST libs.)

  • Re: In-band vs. out-of-band

    by James Watson,

    Your message is awaiting moderation. Thank you for participating in the discussion.


    2) Publish alternative links so that clients can take advantage of refactored and new functionality and features


    Isn't this the practice that is being challenged?


    2) Define backward and forward compatible media types. i.e. in XML schema, be liberal with XmlAnys so that a schema can be easily extended with additional information. Make new elements and attributes optional in future versions.


    In my experience this does very little to shield you from versioning needs. There are just too many types of changes that adding new elements won't support. Even for those cases where you can solve it in this way, it's difficult to predict where you should add 'Any' elements just in case.


    The key is for both the client and server to be sensitive to what they are receiving. Examine the requests/responses to see exactly what the client or server is telling you what it wants to do. This is so subtly different than what we're used to in traditional distributed computing.


    Isn't that the exactly the kind of thing that WS* does that we are trying not to do with REST? Your statement could be read to mean that the content of requests should contain verbs.

  • Re: In-band vs. out-of-band

    by Jean-Jacques Dubray,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    wow, I can nearly agree with Bill! What a turn of event! Of course James disagrees, so I am not sure that counts. Bookmarks are the certainly the least spoken features in REST.

    designing REST applications is about using as little of out-of-band
    information as possible and relying as much as possible on in-band
    information

    This, IMHO, should be elevated to a core design pattern, RESTful or not.

    Has anyone considered assigning major version to the newwork authority? v2.services.doodle.com ?

  • Re: In-band vs. out-of-band

    by Ganesh Prasad,

    Your message is awaiting moderation. Thank you for participating in the discussion.


    designing REST applications is about using as little of out-of-band
    information as possible and relying as much as possible on in-band
    information

    This, IMHO, should be elevated to a core design pattern, RESTful or not.


    Isn't this the fundamental principle of SOA, anyway (not to be confused with SOAP/WS-*)? Eliminate all implicit dependencies between systems and encapsulate all legitimate dependencies within a "contract", however you define it (doesn't have to be WSDL).

    Regards,
    Ganesh

  • Re: In-band vs. out-of-band

    by Jean-Jacques Dubray,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    Well, that was not in the "4 tenets of SOA" as far as I can tell. The closest was I can remember was that Don Box said once, before he joined the SQL Server team, "[CORBA/DCOM] really assumes shared classes [...] between the two endpoints. [SOA] exists to break this dependency. This is the biggest architectural change but it's profound"

    So I am not sure this has ever been applied widely as part of any SOA implementation. I am not sure JAX-RS is capable of that. RESTfulie, might be the closest.

  • Re: In-band vs. out-of-band

    by James Watson,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    "Service Abstraction" and "Service Loose Coupling" are two of the nine principles of service orientation. This idea also is part some of the other 9 principles. I had never ever heard of the "4 tenets" before now and having read them, I wasn't missing much. The most important contribution Don Box made to SOA was admitting that XML schema languages made SOAP obsolete.

  • Re: In-band vs. out-of-band

    by Jean-Jacques Dubray,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    Well, until we come up with some kind of AI mechanism, "in-band" will still rely on "shared understanding". I am not sure that we are yet to the point where I can ship some kind of machine readable artifact and expect the consumer to have any kind of understanding of its semantics without some kind of a priori "shared understanding", but still that's better than hand crafted URI syntaxes and media types. Maybe that's what REST-* is all about. Bill do you have examples of "in-band information exchanges"?

    Don is an RPC/DCOM guy. I am not sure we could expect him to understand anything about SOA. It is well known that WCF works better when client and server share some classes :-)

    I am now wondering how cohesion plays into an in-band information exchange...

  • Re: In-band vs. out-of-band

    by James Watson,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    Well, until we come up with some kind of AI mechanism, "in-band" will still rely on "shared understanding". I am not sure that we are yet to the point where I can ship some kind of machine readable artifact and expect the consumer to have any kind of understanding of its semantics without some kind of a priori "shared understanding", but still that's better than hand crafted URI syntaxes and media types. Maybe that's what REST-* is all about. Bill do you have examples of "in-band information exchanges"?


    The idea is that the client should only know the root URI. The client should not be constructing URIs 'by hand' or in code. The URIs should be returned by the root service. I did not understand this until recently and I haven't really tried it but that's what I understand "in-band" to mean.

  • versioning of services within a REST-based architecture

    by Boris Lublinsky,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    I think the problem is in the question itself. If I am using REST I am dealing with resources, not services. As a result it is impossible to version services in REST. REST has no services - just resources with methods. This means that the only thing that can be legitimately versioned in REST are resources. This also means that encoding version in the URL is the most reasonable approach comparable with encoding of version in service methods in SOAP.

  • What am I versioning?

    by William Martinez,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    Ok.
    1. Versioning is required when something changes, and we have the old and the new.

    2. We may change the flow. A services is composed of three steps, now we add one more, or we add a conditional.
    In this case, since the Flow in REST should be dictated by the state transfers, and those by hypermedia, we only need to set up the new links and all new service requests should follow along. We should not need versioning. Right?

    3. What if we change the data. I want to add a new field or change the name of one. In this case we have clients that now how to fill in all the data fields from my old format. Using parameters in the type we can tell the service which format are we sending. Thus, you just need to keep backward processing of old formats, or simply tell the client we do not support that using an HTTP response code. Simple.

    4. What if the thing that changes is the resource we are updating? Humm. In this case, it depends on the Mr(t) function. What is the resource?
    a- The latest score results between Argentina and Greece in the world cup
    b- The score at half time between Argentina and Greece in the world cup
    Those two resources may be the same at the end of the halt time, right? But when the second half starts, they become two different resources.
    They have two URLs, the membership function M for (a) at one particular moment may map both URLs to the same representation. Then the mapping can change.
    This is to show that versioning based on URLs may or may not make sense. Versioning of a resource makes sense in time, only if we have a URL that does not move in time, so I can have the access to one point in time.
    Complicated? Yes it is, resources are not as easy. The most important thing is you should not relay on URI composition to detect versions. There should be someone, a resource, you should ask for the list of versions, and it should return a list of links. Clear now?

    Cheers.


    William Martinez Pomares.
    Architect's Thoughts Blogger Twitter

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

BT