Versioning my RESTful service

Topics: Web Api
Sep 27, 2011 at 4:04 PM

I am new to this... I'm trying to use a best practice for versioning my RESTful web service.  It turns out to be relatively straight forward if I want the version number to be part of the url.  If, however, I don't want the version number in the url but instead want it in the requested content type I'm not sure how to proceed.  What I've tried thus far:

Access:application/vnd.me.mine-v2+json

Since different versions need to be serviced by different ServiceContract classes I created different classes and then created a subclass of DelegatingHandler that will parse that from the header and determine the version number.  That part works great but I'm not sure how to proceed from there.  My first thought was to map the services like this:

routes.MapServiceRoute<ContactsApi>( "api/contacts" , config );
routes.MapServiceRoute<ContactsApi>( "v1/api/contacts" , config );
routes.MapServiceRoute<ContactsApiV2>( "v2/api/contacts" , config );

And then in my DelegatingHandler subclass modify the url to insert the version prior to calling base.SendAsync().  My intent was that version specific urls would just be undocumented and the non-version specific url would get the version from the access header and redirect to serve up the correct content.  I can see the url is correctly constructed in my DelegatingHandler subclass and by going directly to that versioned url I know it's responding correctly.  However, when I call base.SendAsync() with the HttpRequestMessage that has my modified RequestUri it just fails with a 404 error.

How should I be versioning my RESTful APIs?

Oct 3, 2011 at 3:24 PM

I'm sure there must be people versioning their APIs so my guess is most people use the url to handle versioning.  I'm going to add an issue suggesting support for an alternate method.

Oct 3, 2011 at 5:38 PM
Edited Oct 3, 2011 at 5:40 PM

I'm very curious to this as well as I would definitely recommend against URL versioning.  As a design decision, our team has decided hold off and cross this bridge when it's time to address breaking changes.

It would be great to open up a line of communication with the WCF team in regards to content versioning, service route registration and dispatching / delegation.

One solution would be to have all your contracts return JsonValue, but this constricts you to a single content-type.  Another would involve Inheritance / KnownType serialization which gets ugly.

Oct 3, 2011 at 8:14 PM

I opened an issue about this... you can go over to issues and up vote it... if enough people care/vote maybe it'll get some attention.

Oct 3, 2011 at 8:54 PM
On Oct 3, 2011, at 6:38 PM, dgdev wrote:

> From: dgdev
>
> I'm very curious to this as well as I would definitely recommend against URL versioning.

Yes, exactly.

Here is how you do it:

http://stackoverflow.com/questions/7619645/how-to-implement-backend-of-api-with-multiple-versions/7620193#7620193

Jan


> As a design decision, our team has decided hold off and cross this bridge when it's time to address breaking changes.
>
> It would be great to open up a line of communication with the WCF team in regards to content versioning, service route registration and dispatching / delegation.
>
> Read the full discussion online.
>
> To add a post to this discussion, reply to this email ([email removed])
>
> To start a new discussion for this project, email [email removed]
>
> You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.
>
> Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com
>
Oct 3, 2011 at 9:36 PM
Edited Oct 3, 2011 at 9:37 PM

Thanks for the reply Jan.

I've read several articles in support for content negotiation via Accept header.  I agree this should be used for client to specify the version they support.  That said, how do you implement this on a backend with WCF WebApi?

For instance, from an example here: http://barelyenough.org/blog/2008/05/versioning-rest-web-services/

GET /accounts/3

Account
Name
EmailAddress

AccountsResource.cs
[WebGet(UriTemplate = "{accountId}")]
public Account GetAccountById(int accountId) { ... }

Now let's introduce a breaking change:

AccountV2
Name
EmailAddresses[]

AccountsV2Resource.cs
[WebGet(UriTemplate = "{accountId}")]
public AccountV2 GetAccountV2ById(int accountId) { ... }

In REST, the URI defines a resource which may have many representations.  The accept header allows us to specify which one we'd like, however, how can we use the same service route yet return two varying versions of that content?  The traditional way would be to introduce either Inheritance or an Interface for our return type and support a KnownTypes collection to the serializer.  Maybe with WebApi we can come up with something a little more elegant.  Just a thought.

Oct 11, 2011 at 11:57 AM

I'm thinking that you could use an HttpMessageHandler rewrite the Uri based on an inspection of the content type. Take a look at the UriFormatExtensionMessageHandler in the samples or look at this video: http://channel9.msdn.com/Shows/Endpoint/endpointtv-WCF-Web-API-with-Glenn-Block

Your ServiceContract would look like this:

AccountsResource.cs

[WebGet(UriTemplate = "v1/{accountId}")]
public Account GetAccountV1ById(int accountId) { ... }

[WebGet(UriTemplate = "{accountId}")]
public AccountV2 GetAccountV2ById(int accountId) { ... }

And the HttpMessageHandler would inherit from DelegatingHandler and do

        protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)       
{
...
request.RequestUri = new Uri(newUri, UriKind.Absolute);
...