@Ditscheridou is correct that there is no single, universal answer. The most appropriate answer is very contextual and depends on the specific use case.
First, it should be clarified that a change, any change, should be considered a breaking change. The established contract is the contract and cannot be broken. Backward compatibility is a fallacy. Many people assume that additive changes are backward compatible, but the server cannot guarantee this is true. Most clients will use a Tolerant Reader to handle changes, but the server cannot be certain a client has done so. The only exception to these rules is if you own both sides and the API is not public. In that case, you know and control what the client can or cannot handle. There are clients out there that perform strict validation in their integration tests that fail if something is missing or something extra is added.
An API version is not like a binary version so you should not apply the binary compatibility rules to a HTTP-based API. Despite being called a version, an API version is much more like a media type as @Ditscheridou eluded to, which is why that is the only method of versioning that Fielding himself has said is valid. You've clearly already gone down the path of versioning by URL segment, so I won't attempt to convince you otherwise. However, you should know that, although it is a popular versioning method, it is not RESTful; it violates the Uniform Interface constraint. For example, myapi/v1/car/42
and myapi/v2/car/42
are not two different cars, they are two different representations. Different representations are facilitated by media type negotiation. The Uniform Interface states that the URL path is the identifier, contrary to some people believing it would just be 42
. It might very well be in some backend data store, but that is an implementation detail. This ultimately means that two different URLs implies two different resources (e.g. cars), which is not the case.
This isn't just some REST and HTTP dogma. This is how it was meant to be implemented. The GitHub API is an well-known example of an API that versions by media type.
The scenario you have described is what I call Symmetrical Versioning. Strictly speaking, this is absolutely not required and there is no reason to not allow services to evolve independently with different versions. The main reason to have such a policy is to make it convenient for clients. It is not so convenient for the server. Every change, to any service, pushes the version forward for every service even if there is no change. There are ways to make the implementation more manageable, but you have to be careful that a change in one version isn't accidentally propagated to another. You'll also want a formal policy, if you don't have one already, such as N-2
to prevent supported versions from growing uncontrollably.
Another problem that you will encounter, if you're using it or care, is HATEOAS. By choosing to put the version in the URL segment, if a client asks for myapi/v2/car/42
and it has hypermedia links to myapi/v1/part/1
, how does the Car service know that? What if the Parts service has versions v1
and v3
, but the Car service only has v1
and v2
? Symmetric Versioning can partially help with this problem because - by policy - it can be assumed that all APIs have an implementation of the same version. However, if your API is public, then there is no way to ensure that it aligns to the client. What if the client only understands myapi/v2/car/42
and myapi/v3/part/1
? This is a very real possibility when the versions are asymmetrical. The server should never assume the API version a client wants; the client should always have to explicitly ask for it. This problem is unique to versioning by URL segment. Other methods do not have this issue because the URLs would always be stable (e.g. myapi/car/42
and myapi/part/1
) and the client would indicate the representation they want by way of query string, header, or media type. This is no different than the client asking for application/xml
versus application/json
.
So which approach is the right way? It depends. There are pros and cons to each approach. Keeping the versions symmetrical will solve some problems, but could make it harder to manage; especially, if you ever break up the codebase. Do all the versions need to be symmetrical, even if there is no change - no. If you provide a managed client for your API, that is another way you can help clients avoid the challenges of aligning versions. Furthermore, you might version the client in a consistent, linear way even though the API versions are asymmetrical behind the scenes. This is a common approach and the consumer of the managed client library is never the wiser to the underlying API versions.