tags:

views:

212

answers:

9

I am building an API which I intend to upgrade over time. Is it ever reasonable to include a version number as an argument in the API?

I'm writing a key/value store API in Ruby, Java, Erlang, and C#. I want to build something that is extensible as I know there are many things I have not thought of yet that may have to be incorporated in the future. However, I want to know if there is a clean way of doing this and whether version numbers play a part in this too.

+1  A: 

Yes, take for example Google Maps:

<script type="text/javascript">
  google.load("maps", "2");
</script>
JRL
Do google do this because it is not backwards compatible?
Zubair
+6  A: 

You can do it, it's better (IMHO) if you just make your API backwards-compatible though. It's generally easier, as you don't need to branch on your side, based on the version number, you just re-implement the given method.

I suppose it's really quite implementation-specific (and also environment-specific). I'd do whatever seems easiest/better.

I'd say as long as your maintaining backwards compatibility in some fashion, then it's all good.

Noon Silk
This sounds very sensible, maintaining backwards compatibility instead. So maybe using version numbers is an anti/pattern or code smell type of thing
Zubair
Why does it have to be a choice of "version" or "don't version, maintain backwards-compatibility" -- versioning ALLOWS you to maintain backwards compatbility by knowing what a client is expecting based on its version number. If you don't use versioning, whatever you write will have to stay with you forever, if you change it, you break all clients. Developers aren't perfect, approaches and requirements change. Versioning allows you to be flexible to that change.
Andy Shellam
I guess I didn't know if it was a choice of "version" or "don't version", but if possible I'm thinking its better not to version as I always want people to be able to use the latest version of the API.
Zubair
+3  A: 

Firstly, what type of API are you meaning - a library that applications link against, or an XML/RPC API? I'm going to assume the latter in my answer.

Definitely - it's the only way that your API and/or the client can distinguish which methods/parameters are available to them. It also allows you to continue serving old clients with a new version of the API.

Something I've found works well in the past, is to have some form of handshake method, where the client tells the server which version it is expecting. The server then responds with its current version, and can optionally decide to not support that client (allowing you to phase out an older version, then stop supporting it further down the line, requiring clients to have been updated.)

As for a library, you should definitely include a version number so that applications can link against different versions, and can continue using an older version even if a newer one exists until the application has been upgraded to handle the new version.

Andy Shellam
An API that applications link against I think.
Zubair
Then definitely yes. There are times when it is desirable to change an interface because the needs of the library changed. Signifying a major jump in version number allows you to do this, while still maintaining previous applications (as they link against the previous version of the library.) The UNIX way of doing things (soname) is a pretty good example.
Andy Shellam
But I need something that works across languages and OSes. Maybe I misunderstood?
Zubair
Your library will be coded differently for different OSes (you cannot build a C# library and expect it to compile on a Unix/Linux machine.) Unless you actually mean you'll be creating some form of XML webservice with a common structure that different languages can use (XML as the common element.) In which case you're not talking about a physical DLL/library that applications link against. .NET has a similar form of versioning as Unix except it uses four version components (1.2.3.4) compared to UNIX's soname minor/major (1.2.)
Andy Shellam
Ok, makes a bit more sense now. I guess I was thinking more of compatibility at the source code level, but yes, I need to think in terms of DLLs and jars too I think.
Zubair
+5  A: 

That could be reasonable if you're building an object oriented API and you give the version number to a factory. It's common in dynamic data centric APIs as well - you ask the library for data and have to indicate what format/version you want the data back as.

More commonly for "traditional" libraries(as in the ones you link to in your C/C++/.NET applications) done is:

  • provide an API to fetch the version number of the library. This allows the application to decide if it needs a newer/older version of the library.

  • be backwards compatible as long as you can.

  • Add functions, don't change them. If you have to add arguments/input or change behavior - create a new function rather, and keep the old one around.

  • when you eventually have to break backwards compatibility and get rid of all the old cruft kept around only for the sake of being backwards compatible, have a sane version scheme that clearly indicates incompatible versions.

nos
but if you add functions doesnt it make the names of the functions increasingly complicated?
Zubair
It does, but being backwards compatible is often more important.
nos
Yes, I see. Backwards compatibility is the most important thing for me.
Zubair
+3  A: 

Firstly, it's hard to be specific without knowing what language your API is for.

I think it would be acceptable to allow a version number on the creation of an Object. So that you could create a version 1 or version 2 MyApi object, with different versions of the Object having different methods. It should still be possible to create version 1 obejcts with the version 2 API so users of the library can upgrade gradually.

I don't think you should version numbers on methods or function calls. To me this seem like adding boilerplate to every single call to your API. In this case consider using either optional parameters so you can extend without breaking backwards compatibility and deprecating methods where necessary.

Dave Webb
One API, four languages:Ruby, Java, Erlang, and C#.
Zubair
+1  A: 

Yep it is very sensible, especially if you are using a system built on marshalling / unmarshalling and interfaces (COM / CORBA / SOAP). It is even useful in monolithic applications.

However this approach is suited for very complicated software projects, and if you don't need it, don't use it -- you can get yourself entrenched in a never-ending version-hell.

edit: You might want to look at Apache Thrift (sparsely documented) for data interchange, or Protocol Buffers (less languages supported)

Hassan Syed
By "complicated" do you mean a large SOA system comprised of many different applications for example where different systems are using different versions of an API?
Zubair
yep that would be an example of complicated.
Hassan Syed
+4  A: 

I've used several APIs that support some kind of versioning, most notably ODBC. None of these allowed versioning at the API call level - they all required you to tell the library which version you wanted to work with on an one-off basis - something like:

MyAPI::UseVesion( 2, 1 );

Personally, I would avoid this path if at all possible (make your new APIs backwards compatible) and for sure versioning at the individual call level would be intolerable and unworkable. Imagine code like:

MyAPI::Handle h = MyAPI::GeHandle( 2, 1 );    // get 2.1 version of handle
MyAPI::UseHandle( 3, 0, h );                   // use it somehow with a 3.0 function

You can't detect the mismatch at compile time, and it may or may not work at run time. Yechh!

anon
I think you explained it well Neil. I can really see now how a versioned API will be horrible for all its users
Zubair
Excellent description, Neil! I tried to say the same, but your example makes it much clearer.
Christopher Oezbek
+3  A: 

Yes, allowing version numbers in APIs is reasonable but I would limit passing them to a single method in a MetaAPI, by which the user of your API retrieves a particular version of it.

For each version use a different interface and never change it once it has been released.

This makes backwards compatibility much easier.

Christopher Oezbek
A: 

One thing you'll want to do is provide functions that take version numbers and make sense of them. Functions like:

def has_extended_key_format(version):
    return version > 3

or:

#define HAS_EXTENDED_KEY_FORMAT(version) ((version) > 3)

(Yes, use #define for C and C++, so the preprocessor can do things based on version at compile time.)

This way, your code is not loaded with Magic Numbers in your version checks, and people can read your code and know what feature you're really checking for.

Mike D.
My thoughts exactly. This looks like a pretty clean solution.
Andy Shellam