Aspnet-api-versioning: Versioning method choice implications

Created on 20 Jan 2018  路  8Comments  路  Source: microsoft/aspnet-api-versioning

Like many others, we have a REST API already in production, and would like to add versioning to it.
After reading both the wiki and the REST API guidelines, we're still debating on the implications of each of the "URL segment" and "query string" methods.
I know the choice isn't a clear cut, but I was hoping to clarify the implications from the versioning implementation perspective, and from your vast experience.

Let me try to phrase some concrete questions:

  1. How would the developers of the API be affected in the future when updating, deprecating and extending the existing API, comparing the two methods? Is one of them easier to maintain than the other? How?
  2. I know you're a fan of the query string method, due to the fact that the URL is static that way. It's also mentioned in the guidelines:
    > Services that guarantee the stability of their REST API's URL paths, even through future versions of the API, MAY adopt the query string parameter mechanism

Can you please provide an example for when it's required, and why is changing the query parameter doesn't count as a URL change?

  1. Also from the guidelines:
    > Services that cannot ensure URL path stability across future versions MUST embed the version in the URL path

I don't understand why in this case the query string method is not also possible. Are you able to explain it better?

  1. Is any of the methods better for routing to the correct API when referring to versioned sub-resources? Which one is better to get version 2 of books:
    api/v2/customers/123/books // version 2 of books
    api/customer/123/books?api-version=2 // version 2 of books

What if the 'customers' service now has version 2? wouldn't the URL stay the same in both cases? How would we disambiguate the requested API?
api/v2/customers/123/books // version 2 of books, or books of version 2 of customers?
Maybe this is a pitfall for both methods...

Your help is much appreciated!

answered question

Most helpful comment

Good questions. Hopefully, this will be useful to others that spelunk the issues to gain insight into their decision-making process.

Service Authoring
API versioning supports 4 methods of versioning out-of-the-box:

  • By query string
  • By URL segment
  • By header
  • By media type

You can choose any particular method or combine methods together. Generally, methods only need to be combined when supporting legacy scenarios when versioning methods/conventions have changed.

In general, all of the methods have roughly the same amount of effort to apply API versioning. The design goal was always to _bolt on_ API versioning metadata to the existing routing infrastructure to minimize the learning curve. API versioning itself does not change the behavior of routing. This allows you to continue using routing the way you always have. Normally duplicate routes would be conflicting. API versioning uses the _API version_ metadata to disambiguate matching route candidates to resolve the _most_ appropriate match or fail with the same type of ambiguous behavior you would get without API versioning.

Of all the methods, versioning by URL segment can have the most complexity and maintenance cost. First, you must use the API version route constraint in your URL templates; otherwise, API versioning doesn't know how to extract the value (no _magic_ string parsing). This effort isn't enormous, but service authors now need to know that they need to include this constraint in their templates. For example, api/v{version:apiVersion}/books. This requirement is so small that it's unlikely to discourage the approach.

The complexity comes in when you want to also support a _default_ or _implicit_ matching of the current version. It's not something that I encourage, but sometimes it's required. The main reason for this functionality at all was for backward compatibility when transitioning to API versioning. When versioning by URL segment, it's not possible to automatically fill in a default route parameter value in the middle of the URL. Even though you can author a template like api/v{version:apiVersion=1.0}/books, it will never match api/books/. This is in part because v is not part of the API version, but also because the routing system only supports defaults at the end of the route template. In order to support default routes by URL segment, the service author has to define two routes per service: api/books and api/v{version:apiVersion}/books. If the default route follows the current implementation, then that means that the service author has to move the template from the old implementation to new when API versions change. Again, this isn't super difficult to do, but it become tedious or even untenable for large APIs.

Defaulting to the Query String Method
There is arguably a lot of philosophy and dogma around whether API versioning is necessary and which method is the _right_ one. Fielding himself as argued against needing API versioning (as conventionally presented). Much of REST revolves around the notion of thinking in terms of _resources_. Support for API versioning, therefore, should not be thought of as calling a _version_ of a method or API, but instead as returning or behaving as a specific _representation_ of that resource. As Fielding and others have pointed out, the _most_ RESTful way to achieve that is through media type negotiation, which is a supported method by API versioning.

If one embraces the thinking of resources, then the _Uniform Interface_ constraint tells us that the path in a URL identifies a resource. The query string is not part of the path and is, therefore, not identifying. Some will say that api/books?id=42 is RESTful, but I would argue that it's not. The query string is not part of the path. I'm also aware of any web server or web API technology stack that will route based query string. I don't know that I'm a _purist_, but I've read Fielding's dissertation and paid close attention to the constraints outlined by REST. If you accept that the API version is just a different representation (and perhaps behavior) of a resource, then the API version does not belong in the URL path. For example, the resource api/book2/42 is always _"Book 42"_ regardless of what representation or API version you ask for. When the API version is in the URL path, then the URLs api/v1/books/42 and api/v2/books/42 _imply_ that there are two different _Book_ resources when they are logically the same (but albeit different representations).

All of that is fine and good, but pragmatically, the most common forms of API versioning tends to be either by URL segment or query string. An ancillary design goal was to provide a working, out-of-the-box setup with minimal configuration. To that end, defaulting to the query string aligns closest to the REST principles (IMO) and offers the greatest amount of flexibly. Query strings, unlikely URL segments, can have default values, so if supporting that scenario is desired or needed, it's effortless to enable. Although the media type method is perhaps the most ideal way to API version, it's not the simplest for clients to use; especially JavaScript clients. The query string method (or even the URL segment method) is easier for these clients to consume (since there are no headers to set). I've also found from experience that the query string method results in more predictable URLs for clients. When or things change, or something new is added, they always know the API version is just appended to the query string of any URL.

Imagine if you were building a strong client abstraction to the API in your language of choice (C#, Java, JavaScript, etc). In all likelihood, the API version would be a parameter to the constructor - something like new ApiClient("2.5"). When a URL segment is used, that means the client code has to have a mapping or perform some type of string manipulation or formatting to build the correct server URLs. Using the query string method, a client can consistently append the query string after everything else.

For all of those reasons and alignment to prescribed Microsoft, this is way the query string method is the default. If you want or care about being truly RESTful, then media type negotiation aligns closest to the _Uniform Resource_ constraint.

URL Path versus Query String
I've largely discussed the differences in the previous section, but since there was a specific question about URLs, I want to reiterate. While it might be subtle, I do try to make sure I use explicit language; especially for documentation. Yes, it is true that the query string does change the entirety of a URL; however, that is not the argument I'm making. Only the URL path identifies a resource or at least in any practical implementation of web servers that I've seen. The path component is the identifying part of a URL. The query string is more a like a set of conditional options. The API version option might change, but the _path_ and, hence, _identifier_ of the resource stays the same. Ultimately, there is less varability in the query string method for many reasons as I mentioned above.

While I tend to have rationale for the query string method, I've never heard much argument or rational for the URL segment method other than because it was some prior art (e.g. _"Well, that's how [insert company] does it."_). For those that really want to debate things, both methods are _wrong_. Media type negotiation is the only truly RESTful mechanism in aligning to the constraints and intention (e.g. API version is indicating a _version_ of a resource as opposed to a different resource).

Nested Resources
For _parent-child_ relationships, a service should support _containment_. In other words, you should be able to reference children without their parents. This simplifies things immensely and makes it pretty obvious that the parent and child have the same API version. The most ubiquitous example of this is a the _Order -> Line Item_ relationship. A line item cannot stand on its own and it's nonsensical for the two to have different API versions.

Having URLs that looks like api/v1/customers/books/42?api-version=2.0 is horrible. While it's technically possible to configure this scenario within API versioning, it will fail at runtime. This type of versioning is super confusing and ugly to look at. While API versioning does allow an API version to be specified multiple times, one of the built-in validations is to ensure that all requested API versions are the same. This means only a URL like api/v1/customers/books/42?api-version=1 would be allowed. If they are the same though, then there's no point in specifying them both.

Related Resources
I implicitly read two questions with respect to related resources. In addition to having a _parent-child_ relationship, you might just have two arbitrarily related resources such as _customers_ and _books_. Rather than couple these though URLs, they should be linked together using hypermedia in accordance with the _Uniform Resource_ constraint. For example, api/customers/42 might return a hypermedia link to api/books?customerId=42 indicating how to get the books for a customer. The inverse relationship might also be true and have a link like api/customers?bookId=42.

Exactly how to you tie these things together is ultimately up to you, but it's generally best to keep these separate so that they can evolve independently over time. One question that has come up a lot on this topic is whether to include the API version in the query string. While there may be some benefit to doing so, I would say - no. The job of the referring service is only to identify and tell the client where to find the resource. Specifying the API version in related links would introduce coupling that you don't what. The referring service would have to know which API versions are available and add them to URLs. What happens the API versions between services are incongruent/asymmetrical? What if the client wants a different version of a resource than what the referring service provided? This decision should be in the hands of the client and, therefore, the API version should be omitted in such links.

As an aside, this highlights another limitation of URL segments. The coupling and specific API versions cannot be avoided using this approach because the API version is directly embedded in the URL. It's reasonable for APIs to evolve at different speeds and versions over time; therefore, it's very feasible to foresee a client requesting customers (v1.0) and books (v2.0).

Conclusion
The final decision and philosophies you choose to adopt are solely up to you. My opinions should not be necessarily weighed any stronger than the many opinions on the web. Most of my assertions are based on the practicality of what works and what doesn't (or is difficult) from experience. May you find this useful.

All 8 comments

Good questions. Hopefully, this will be useful to others that spelunk the issues to gain insight into their decision-making process.

Service Authoring
API versioning supports 4 methods of versioning out-of-the-box:

  • By query string
  • By URL segment
  • By header
  • By media type

You can choose any particular method or combine methods together. Generally, methods only need to be combined when supporting legacy scenarios when versioning methods/conventions have changed.

In general, all of the methods have roughly the same amount of effort to apply API versioning. The design goal was always to _bolt on_ API versioning metadata to the existing routing infrastructure to minimize the learning curve. API versioning itself does not change the behavior of routing. This allows you to continue using routing the way you always have. Normally duplicate routes would be conflicting. API versioning uses the _API version_ metadata to disambiguate matching route candidates to resolve the _most_ appropriate match or fail with the same type of ambiguous behavior you would get without API versioning.

Of all the methods, versioning by URL segment can have the most complexity and maintenance cost. First, you must use the API version route constraint in your URL templates; otherwise, API versioning doesn't know how to extract the value (no _magic_ string parsing). This effort isn't enormous, but service authors now need to know that they need to include this constraint in their templates. For example, api/v{version:apiVersion}/books. This requirement is so small that it's unlikely to discourage the approach.

The complexity comes in when you want to also support a _default_ or _implicit_ matching of the current version. It's not something that I encourage, but sometimes it's required. The main reason for this functionality at all was for backward compatibility when transitioning to API versioning. When versioning by URL segment, it's not possible to automatically fill in a default route parameter value in the middle of the URL. Even though you can author a template like api/v{version:apiVersion=1.0}/books, it will never match api/books/. This is in part because v is not part of the API version, but also because the routing system only supports defaults at the end of the route template. In order to support default routes by URL segment, the service author has to define two routes per service: api/books and api/v{version:apiVersion}/books. If the default route follows the current implementation, then that means that the service author has to move the template from the old implementation to new when API versions change. Again, this isn't super difficult to do, but it become tedious or even untenable for large APIs.

Defaulting to the Query String Method
There is arguably a lot of philosophy and dogma around whether API versioning is necessary and which method is the _right_ one. Fielding himself as argued against needing API versioning (as conventionally presented). Much of REST revolves around the notion of thinking in terms of _resources_. Support for API versioning, therefore, should not be thought of as calling a _version_ of a method or API, but instead as returning or behaving as a specific _representation_ of that resource. As Fielding and others have pointed out, the _most_ RESTful way to achieve that is through media type negotiation, which is a supported method by API versioning.

If one embraces the thinking of resources, then the _Uniform Interface_ constraint tells us that the path in a URL identifies a resource. The query string is not part of the path and is, therefore, not identifying. Some will say that api/books?id=42 is RESTful, but I would argue that it's not. The query string is not part of the path. I'm also aware of any web server or web API technology stack that will route based query string. I don't know that I'm a _purist_, but I've read Fielding's dissertation and paid close attention to the constraints outlined by REST. If you accept that the API version is just a different representation (and perhaps behavior) of a resource, then the API version does not belong in the URL path. For example, the resource api/book2/42 is always _"Book 42"_ regardless of what representation or API version you ask for. When the API version is in the URL path, then the URLs api/v1/books/42 and api/v2/books/42 _imply_ that there are two different _Book_ resources when they are logically the same (but albeit different representations).

All of that is fine and good, but pragmatically, the most common forms of API versioning tends to be either by URL segment or query string. An ancillary design goal was to provide a working, out-of-the-box setup with minimal configuration. To that end, defaulting to the query string aligns closest to the REST principles (IMO) and offers the greatest amount of flexibly. Query strings, unlikely URL segments, can have default values, so if supporting that scenario is desired or needed, it's effortless to enable. Although the media type method is perhaps the most ideal way to API version, it's not the simplest for clients to use; especially JavaScript clients. The query string method (or even the URL segment method) is easier for these clients to consume (since there are no headers to set). I've also found from experience that the query string method results in more predictable URLs for clients. When or things change, or something new is added, they always know the API version is just appended to the query string of any URL.

Imagine if you were building a strong client abstraction to the API in your language of choice (C#, Java, JavaScript, etc). In all likelihood, the API version would be a parameter to the constructor - something like new ApiClient("2.5"). When a URL segment is used, that means the client code has to have a mapping or perform some type of string manipulation or formatting to build the correct server URLs. Using the query string method, a client can consistently append the query string after everything else.

For all of those reasons and alignment to prescribed Microsoft, this is way the query string method is the default. If you want or care about being truly RESTful, then media type negotiation aligns closest to the _Uniform Resource_ constraint.

URL Path versus Query String
I've largely discussed the differences in the previous section, but since there was a specific question about URLs, I want to reiterate. While it might be subtle, I do try to make sure I use explicit language; especially for documentation. Yes, it is true that the query string does change the entirety of a URL; however, that is not the argument I'm making. Only the URL path identifies a resource or at least in any practical implementation of web servers that I've seen. The path component is the identifying part of a URL. The query string is more a like a set of conditional options. The API version option might change, but the _path_ and, hence, _identifier_ of the resource stays the same. Ultimately, there is less varability in the query string method for many reasons as I mentioned above.

While I tend to have rationale for the query string method, I've never heard much argument or rational for the URL segment method other than because it was some prior art (e.g. _"Well, that's how [insert company] does it."_). For those that really want to debate things, both methods are _wrong_. Media type negotiation is the only truly RESTful mechanism in aligning to the constraints and intention (e.g. API version is indicating a _version_ of a resource as opposed to a different resource).

Nested Resources
For _parent-child_ relationships, a service should support _containment_. In other words, you should be able to reference children without their parents. This simplifies things immensely and makes it pretty obvious that the parent and child have the same API version. The most ubiquitous example of this is a the _Order -> Line Item_ relationship. A line item cannot stand on its own and it's nonsensical for the two to have different API versions.

Having URLs that looks like api/v1/customers/books/42?api-version=2.0 is horrible. While it's technically possible to configure this scenario within API versioning, it will fail at runtime. This type of versioning is super confusing and ugly to look at. While API versioning does allow an API version to be specified multiple times, one of the built-in validations is to ensure that all requested API versions are the same. This means only a URL like api/v1/customers/books/42?api-version=1 would be allowed. If they are the same though, then there's no point in specifying them both.

Related Resources
I implicitly read two questions with respect to related resources. In addition to having a _parent-child_ relationship, you might just have two arbitrarily related resources such as _customers_ and _books_. Rather than couple these though URLs, they should be linked together using hypermedia in accordance with the _Uniform Resource_ constraint. For example, api/customers/42 might return a hypermedia link to api/books?customerId=42 indicating how to get the books for a customer. The inverse relationship might also be true and have a link like api/customers?bookId=42.

Exactly how to you tie these things together is ultimately up to you, but it's generally best to keep these separate so that they can evolve independently over time. One question that has come up a lot on this topic is whether to include the API version in the query string. While there may be some benefit to doing so, I would say - no. The job of the referring service is only to identify and tell the client where to find the resource. Specifying the API version in related links would introduce coupling that you don't what. The referring service would have to know which API versions are available and add them to URLs. What happens the API versions between services are incongruent/asymmetrical? What if the client wants a different version of a resource than what the referring service provided? This decision should be in the hands of the client and, therefore, the API version should be omitted in such links.

As an aside, this highlights another limitation of URL segments. The coupling and specific API versions cannot be avoided using this approach because the API version is directly embedded in the URL. It's reasonable for APIs to evolve at different speeds and versions over time; therefore, it's very feasible to foresee a client requesting customers (v1.0) and books (v2.0).

Conclusion
The final decision and philosophies you choose to adopt are solely up to you. My opinions should not be necessarily weighed any stronger than the many opinions on the web. Most of my assertions are based on the practicality of what works and what doesn't (or is difficult) from experience. May you find this useful.

Thanks a lot for the detailed explanation!

No problem. I hope it helps you and others who are seeking input into their decision-making process.

As an issue, I think this is now resolved. I'll scavenge my philophical musings into the wiki or a blog post at some point. Thanks.

Hi,
If you don't mind, I'd be happy to better understand the difference between the query string and URL segment approaches from the client POV.

You wrote:

Imagine if you were building a strong client abstraction to the API in your language of choice (C#, Java, JavaScript, etc). In all likelihood, the API version would be a parameter to the constructor - something like new ApiClient("2.5"). When a URL segment is used, that means the client code has to have a mapping or perform some type of string manipulation or formatting to build the correct server URLs. Using the query string method, a client can consistently append the query string after everything else.

Can you elaborate on which mapping/manipulation you're referring to? with the URL segment approach, wouldn't it also be able to construct the base URL with the version, e.g. /api/v2.5/ and then every call would concatenate the resource and the necessary params? Maybe I'm missing something, but isn't the query string approach actually means the client MUST use an abstraction for calling the API, otherwise they would have to add the version explicitly to every call?
In our case, we have one version for the whole API (when we introduce version 2.5, all our endpoints get this version, even if not changed). In that case, changing the version requested by the client should ideally be in one place and not per call. With URL segment, I can have one base URL of version 2.4 .../api/v2.4/ which I use to construct my requests (even without an abstraction), and changing that URL to .../api/v2.5/ in one place would be easy, probably with a out-of-the-box client class. Would it be easy also when using query strings? From what I know there's no way to set a query string parameter that is automatically sent with every request you make.
I hope I explained myself well...

Your thoughts are most welcome - we're very close to going live, and one of my colleague raised this concern after we've already implemented versioning by query string (and by namespace in the code)...

Thanks!

First, yes - it's relatively just as easy to concatenate a URL with the API version in it, but you shouldn't have to. Yes - you still have to add a query string parameter, but it already has strong, generic semantics that you can use to test and/or append the API version as necessary. If you use the URL segment, you must know exactly where and how to do this. It _could_ change over time.

I don't know all the particulars of your scenario or service topology, but services are meant to evolve independently over time. They might all start the same version, but they often don't stay that way. If you're forcing everything to a single version, that will work, but may be extra work for you or clients. Your client technology stack determines how easy it to append the API version. There are quite a few straight forward ways to do this in .NET. Here's an example in an API test suite I have for another project where I do that very thing. Appending a query string is easy and consistent. Modifying the path (e.g. URL segment) means you must know how the path is constructed. If the path has consistent semantics, then it works reasonably well. You're always succeptible to changes though. What that means is that any desire to change path conventions has to consider existing clients. That's not the case with a query string unless you decide to dump the query string all together.

I would argue that the nominclature of an _API version_ is really about a resource _representation_ as opposed to a _version_. This is probably why Fielding himself has ranted many times about the why API versioning shouldn't exist. The only real approach that matches is media type negotation because this is how a client asks for a representation in HTTP while complying with the REST constraints. In the same sense, an _API version_ is an additional part to the representation of a resource. In accordance with the REST constraints, a URI/URL is the identifier of a resource. While a URL can have many constituent parts, the path is the part that is the identifier. Although the URL segment is popular, this is what has convinced me it's the wrong approach.

If my services (e.g. API) returns orders, then I should able to get to order _123_ with something like orders/123. Some variation in representation and even behavior may change over time; hence, versioning. The URL segment methodology would recommend having v1/orders/123 and v2/orders/123. This doesn't make any sense to me. Both URLs refer to the same order behind the service (probably in a persistent store like a database). However, since the version is in the path, by rule of REST they are different orders, which is not true. You don't expect the OrderId column in storage to change between versions do you? More likely that not, what's different is the representation of the order. For example, you may have added some new order attributes. This should not change the URL or identifier of the order. Using the query string methodology, you are effectively asking for a _representation_ without changing the path. If we get pedantic, then media type is even better and the URL is the URL. Depending on your clients, using a query string tends to be more pragmatic than specifying a media type (ex: accept: application/json; v=1.0), even though that would be the _true_, RESTful way. Configuring headers isn't hard, but it's not as _convenient_ as adding a query string or even changing the path for that matter. GitHub is an example of a well-known API that versions by media type (which is also supported by these libraries ;))

If following the REST constraints is important to you, then there are other issues to consider with the URL path method (as I believe I mentioned above). Specifically, if you want to support HATEOAS, you'll run into problems with the URL method. Let's say an order has an associated customer. Using HATEOAS, an order resource might contain additional metadata like this:

HTTP/1.1 200
host: localhost
content-type: application/json

{
   "id": 123,
   "created": "2018-07-24",
   "links": [{"name": "Customer", "href": "http://localhost/customers/456"}]
}

This is effectively saying:

_If you'd like to get information about the associated customer, please go to 'http://localhost/customers/456'_

Links typically should be absolute because there is no guarantee that the Customer resource is on the same server as the Order resource. Even if it was, you might want to change it later for scale out, etc. You don't want a client relying relative URLs.

Now, if all your APIs always have the same version, then the URL method can work. However, except for closely bound resources, I've always seen them drift apart over time. As a service taxonomy grows, it's hard to have all teams lock-step all the time. You also stymie agile because you have to change existing services to declare the new API version, even if the only thing that changed is bumping the version. In addition, if you choose the URL segment and you want to do HATEOAS, you basically have to version all resources the same; otherwise, clients run into problems. Let's consider that Customer is now 2.0. This should mean the response now looks like:

HTTP/1.1 200
host: localhost
content-type: application/json

{
   "id": 123,
   "created": "2018-07-24",
   "links": [{"name": "Customer", "href": "http://localhost/v2/customers/456"}]
}

The issue here is v2. If the Order resource is 1.0, how does it know that the Customer resource should be 2.0? To support that, you'd have to do one or more of the following:

  • List the link for every API version and let the client pick

    • The client also needs to know how to parse the URL to pick the one they are looking for

  • Always provide the latest, but you still have to know what that is
  • Maintain a mapping or provide some other convention of knowing which version to pick

To throw one more wrench into the machine, consider that the Customer supports multiple versions. How would the Order resource know which version the client wants? Simple - it doesn't ... and shouldn't know. It's better to provide the link at let the client choose which version (e.g. _respresentation_) they want.

Again, if all your APIs use the same version, all the time, the URL segment can work. Hopefully, that helps illustrate how the URL method can be rigid. Once you go down that path, it's hard to change from. Of all the methods of versioning, I like the URL method the least because I don't feel like my resource identifiers should be changing between versions.

I hope you find that useful.

Thanks again for the detailed answer!

Can you please give an example of how the path construction can change over time? if I put the version right after the 'api', and decide it's in the format 'v{version}', what could be the reason for ever changing it? You mean that different services might decide differently?
For that matter, I can also change the query string parameter name and I'd have to consider existing clients... how is that different? I'm probably missing something...

Thanks!

So imagine you started with api/v1/orders/123 and then decided that the api prefix doesn't make any sense because everything is an API or you might use v1/api/orders/123 where things are switched around. You might consider v2/orders/123 and that would be totally valid, but the URL is unstable. Since the URL is the identifier, it shouldn't be changing. Anyone that ever used the api will likely encounter this issue. It's not an unsolvable, or even hard problem, to detect for client, but it is - what I would consider - a violation of POLA. The inverse is equally true if you went from no prefix to ~/api.

The same is not true of the query string. Yes - it will break if you change the name or change the root path, but otherwise things are stable. If you did choose to change the parameter name, this is handled pretty easily by mapping multiple names. The same is not possible with URL segments. You would have to define multiple routes. For example, consider you now allowed the shorter version query string. Both can live side-by-side as:

| URL | Result |
| ---- | ------- |
| orders/123?api-version=2.0 | 200 |
| orders/123?version=2.0 | 200 |
| orders/123?api-version=2.0&version=2.0 | 200 |
| orders/123?api-version=1.0&version=2.0 | 400 |

It'd be weird, but a client _could_ ask for multiple API versions. If they are different, then that is a 400; otherwise, the one selected is irrelevant because they are all the same value.

Another thing to consider is changing versioning styles or supporting _default_ versions. I generally don't recommend it and it was meant for backward compatability (not your case), but I've seen a great many people use the AssumeDefaultVersionWhenUnspecified = true. This feature simply cannot work with URL segment because the version is part of the path. It's impossible to _automagically_ fill in the path segment with a default value (though people have asked). Perhaps you decide one day that media types are superior to a query string. This change doesn't affect the path at all.

In the end, there are no concrete rules. I would surmise that the URL method is the least compliant with Fielding's constraint model, but that doesn't mean it doesn't work. Much of the ultimate direction is choice and preference. Don't take my musings as an rule of thumb though.

Was this page helpful?
0 / 5 - 0 ratings