# REST and backward compatibility

**URL:** <https://www.ruby-forum.com/t/rest-and-backward-compatibility/128432>\
**Category:** Rails\
**Created:** [February 7, 2008, 5:25pm UTC](https://www.ruby-forum.com/t/rest-and-backward-compatibility/128432 "2008-02-07T17:25:06Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Bas\_van\_Westing](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/85f322/32.png) [@Bas\_van\_Westing](https://www.ruby-forum.com/u/Bas_van_Westing)\
**Post date:** [February 7, 2008, 5:25pm UTC](https://www.ruby-forum.com/t/rest-and-backward-compatibility/128432/1 "2008-02-07T17:25:06Z")

</div>

Hi,

I’m struggling with the backward compatibility of a RESTful interface.  
I can’t find any documentation on the standard way to solving this. I  
know that as long as you only extend the RESTful interface there is no  
backward compatibility issue, but I don’t believe that is a very  
realistic situation (I refactor a lot). Say you want to change an  
attribute’s name, how would you solve this?

For the solution I’ve got the following assumptions:

- The interface version should not be placed in the URL (i.e.  
[www.mydomain.com/v2/books](http://www.mydomain.com/v2/books)). The URL defines the resource, the  
interface version is not part of the resource in my opinion.
- The interface version should not be placed in the parameters (i.e.  
[www.mydomain.com/books?version=2](http://www.mydomain.com/books?version=2)). This is an option, but it would  
pollute my urls.
- Only the first interface version can be defaulted, because changing  
the default will break existing client implementations using the  
previous default. So this default is not really usefull in the long  
run, since only version 1 can use it. But at least this would allow  
people to leave out the interface version description, if they don’t  
have to be backward compatible.

I believe that an ideal solution to this would be to place the version  
in the HTTP headers. Only there is no standard defined for it as far  
as I can see. But it would be like the following:

POST [www.mydomain.com/books](http://www.mydomain.com/books) HTTP/1.1  
Interface-Version: 2  
Content-Type: application/xml  
Accept: application/xml

…

For the controller we could then apply a before\_filter which rewrites  
the param hash to the latest interface version (after determining the  
used interface version from the header). The latest interface  
definition is then used in the controller actions.

I think this can be quite clean.  
Does anybody have know of a standard solution for this problem?

Regards, Bas

---

<div class="post-metadata">

**Author:** ![Bas\_van\_Westing](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/85f322/32.png) [@Bas\_van\_Westing](https://www.ruby-forum.com/u/Bas_van_Westing)\
**Post date:** [February 7, 2008, 5:49pm UTC](https://www.ruby-forum.com/t/rest-and-backward-compatibility/128432/2 "2008-02-07T17:49:22Z")

</div>

[edit\_by\_author]  
The third assumption is incorrect. You must default the last version,  
otherwise the non webservice clients (browsers etc.) would get into  
trouble. But this does create another issue that every webservice  
client must use the version number from the start, also for version 1.  
[/edit\_by\_author]

---

<div class="post-metadata">

**Author:** ![Bas\_van\_Westing](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/85f322/32.png) [@Bas\_van\_Westing](https://www.ruby-forum.com/u/Bas_van_Westing)\
**Post date:** [February 7, 2008, 7:07pm UTC](https://www.ruby-forum.com/t/rest-and-backward-compatibility/128432/3 "2008-02-07T19:07:27Z")

</div>

I don’t think you should bother with version numbers, it’s RPC-like. Why  
do  
you want to keep an old version of the service alive? I would just force  
the  
clients to an update, or provide a new service for the updated  
resources. But  
if you want to use a version number, both examples are equal. All the  
information that the server needs to fulfill the request should be in  
the  
path. It doesn’t matter much if it’s /v2/books or books?v=2.

I would just fork the project and have it running on diffrent domains,  
or  
rewrite the URL on the incoming webserver to point to different  
applications.  
Maintaining different versions off an API is going to be hell.

---

<div class="post-metadata">

**Author:** ![Bas\_van\_Westing](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/85f322/32.png) [@Bas\_van\_Westing](https://www.ruby-forum.com/u/Bas_van_Westing)\
**Post date:** [February 7, 2008, 10:52pm UTC](https://www.ruby-forum.com/t/rest-and-backward-compatibility/128432/4 "2008-02-07T22:52:36Z")

</div>

Hi Matthijs,

I’m afraid I cannot just force my paying customers to change their  
interfaces. I don’t think you ever can… in real life (only the  
planning and synchronized execution alone would give severe  
headaches).  
Anyway I did some more reading and I think the HTTP Header option is  
not so bad. There are X-Headers which basically are free form. So the  
header would look like the following:

POST /books HTTP/1.1  
User-Agent: ApacheBench/2.0.40-dev  
Authorization: Basic YmFzOnRlc3Q=  
Host: [www.mydomain.com](http://www.mydomain.com)  
X-Interface-Version: 2  
Content-Type: application/xml  
Accept: application/xml

The before\_filter is really not so hard to implement. And making the  
interface upgrades cascaded (in case of a version delta \> 1) will only  
require me to add a single mapping for each new interface version,  
only defining the mapping with the previous version. Keeping in mind  
that interface versions are only increased is case of a non-  
incremental extension, I won’t expect to ever go beyond more than 3  
interface versions in practice.

So I think your statement that “Maintaining different versions off an  
API is going to be hell.” is not necessarily the case. As I see things  
now, the backward compatibility issue with RESTful interfaces is  
solvable nicely in Ruby on Rails (or in general).

The only remaining question is: Am I doing something really non-  
standard and is there a better solution?

Regards,  
Bas van Westing

On Feb 7, 6:55 pm, “Matthijs L.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)
