shaswata pal
shaswata pal

Reputation: 425

azure api versioning x-ms-version api-version comparison

I see that in the Microsft managed REST APIs exposed in Azure there are two ways to do versioning a) x-ms-version in header b) api-version in query string

I wanted to understand what is the decision behind the selection between the two. I was reading somewhere that x-ms-versioning is legacy and way forward is the query string versioning mode. Is this correct?

Also as per Scot Hanselman's blog he says Query string parameter is not his preferred way and he would choose the URL Path segment. Then wondering why Microsoft adopted this option? I do agree that each person has his own preference but would be helpful to know the reason for this selection from Microsoft.

Upvotes: 1

Views: 1089

Answers (1)

Chris Martinez
Chris Martinez

Reputation: 4368

The x-ms-version header is legacy and only maintained for backward compatibility. In fact, the notion of using the x- prefix has been deprecated since the introduction of RFC 6648 in 2012.

Using api-version in the query string is one of the official conventions outlined in §12 Versioning of the Microsoft REST API Guidelines. The guidelines also allow for using the URL segment method, but the query string method is the most prolific.

Fielding himself has pretty strong opinions about API versioning - namely don't do it. The only universally accepted approach to implementing a versioned REST API is to use media type negotiation. (e.g. accept: application/json;v=1.0 or accept: application/vnd.acme.v1+json). GitHub versions their API this way.

While media type negotiation abides by the REST constraints and isn't all that difficult to implement, it's the least used method. There are likely many explanations for why, but the reality is that there are at least 3 other very common methods: by query string, by URL segment, or by header.

Pedantic musings aside, the most common forms are likely due to the ease in which a client can access the service. The header method is not much different that using media type negotiation. If a header is going to be used, then using the accept and content-type headers with media type negotiation is a better option. This leaves us with just the query string and URL segment approach.

While the URL segment approach is common, it has a few pitfalls that most service authors don't consider. It's proliferation has very much been, "Well, that's how [insert company here] does it". In my opinion, the URL segment method suffers from the following issues:

  1. URLs are not stable. They change over time with each new API version.
  2. As part of the Uniform Interface the URL path is supposed to identify a resource. If your URL paths are api/v1/products/123 and api/v2/products/123, it implies that there are two different products, which is not true. The v1 versus v2 URL segment is implying a different representation. In all API versions, the resource is still the same logical product.
  3. If your API supports HATEOAS, then link generation is a challenge when you have incongruent resource versioning. Mature service taxonomies and the REST constraints themselves are meant to help evolve services and resources over time. It's quite feasible to expect that api/orders could be 1.0 and a referenced line item with api/products/123 support 1.0-3.0. If the version number is baked into the URL, what URL should the service generate? It could assume the same version, but that could be wrong. Any other option is coupling to the related resources and may not be what the client wants. A service cannot know all of the API versions of different resources a client understands. The server should therefore only generate links in the form of vanilla resource identifiers (ex: api/products/123) and let the client specify which API version to use. Any other manipulation by the client of links greatly diminishes the value of supporting HATEOAS. Of course, if everything is the same version or on the same resource, this may be a non-issue.
  4. 2 and 3 can be further complicated by a client that persists resource links. When an API version is sunset, any old links to the resource are now broken, even though the resource still exists albeit not using an expected, but obsolete representation.

This brings things full circle to the query string method. While it's true that the query string will vary by API version, it's a parameter not part of the identifier (e.g. path). The URL path stays consistent for clients across all versions. It's also easy for clients to append the query parameter for the version that they understand. API versions are also commonly numeric, date-based, or both. Sometimes they have a status too. The URL api/products/123?api-version=2018-03-10-beta1 is arguably much cleaner than api/2018-03-10-beta1/products/123.

In conclusion, while the query string method may not be the true RESTful method to version a resource, it tends to carry more of the expected traits while remaining easy to consume (which isn't a REST constraint). In conjunction with the Microsoft REST API Guidelines, this is why ASP.NET API Versioning defaults to the query string method out-of-the-box, even though all of these methods are supported.

Hopefully, this provides some useful insights as how different styles can affect your service taxonomy aside from pure preference.

Upvotes: 1

Related Questions