bploetz / versionist

A plugin for versioning Rails based RESTful APIs.
MIT License
971 stars 51 forks source link

Single namespace to capture all minor versions #37

Closed stantona closed 11 years ago

stantona commented 11 years ago

I would like to clarify a scenario where I would like a single namespace, say V2 to capture all minor versions, using a scheme such as: 2.0, 2.1, 2.2.. etc. Note there is no "v" prepended to the versions.

From what I can understand from the code, versioning is determined by doing substring matching. If I had something like:

api_version(:module => "V2", :header => {:name => "X-VERSION", :value => "2"}) do
  resources :users, only: [:create]
end

it would seem to match any version with "2" in it, including "1.2".

The only way I can be absolutely sure that the correct version is selected is if I repeat each minor version which seems excessive:

api_version(:module => "V2", :header => {:name => "X-VERSION", :value => "2.0"}) do
  resources :users, only: [:create]
end

api_version(:module => "V2", :header => {:name => "X-VERSION", :value => "2.1"}) do
  resources :users, only: [:create]
end

Ideally I would like a single definition for "V2" module that captures all minor versions. Is this possible for my scheme?

bploetz commented 11 years ago

The fix for Issues #30 and #31 made it so that you no longer get false positives due to substring matches when using the header versioning strategy (see https://github.com/bploetz/versionist/blob/master/lib/versionist/versioning_strategy/header.rb#L24). So as of that fix, all versioning strategies should now only find exact matches (as you've found).

What you're asking for is for a single Module to honor a range of versions, or perhaps an alias-type feature as requested here: https://github.com/bploetz/versionist/issues/18.

While either of these approaches is certainly feasible in theory, I'm curious as to how this would work in practice. By definition a new version of an API is introduced when there's a breaking change made to either the request or response format (or both). If a single Module namespace honors more than one version, then where are you managing these differences?

stantona commented 11 years ago

Similar to #18, our use case involves mobile clients that have different versions. So even though the web version may not change, the mobile client may introduce a new version with no corresponding change to the API.

My initial thinking that it would be good to support regex matching. In other words, if a string is provided, use current stategy, if regex is provided us the regex stategy to support any kind of matching.

bploetz commented 11 years ago

Sorry, still not following your scenario here...

If you release a new mobile client version (say iPhone app goes from 2.0 to 2.1), and doing so doesn't require a change to the back-end API it's running against, then why does the API version need to change in that case? Wouldn't mobile client 2.1 still request API V2? You should only need to change the API version if a breaking change needs to be made to the API itself. It almost seems as if you're conflating the concept of the client version and the API version into a single concept. But they're not, they're separate and distinct things with independent release cycles.

Let me know if I'm just missing something fundamental here. :-)

stantona commented 11 years ago

You're correct, the app was originally setup to recognize client versions, not actual API versions which is what you're suggesting. So given that, we will be fixing this to send the API version to as part of the request (not client version).

But I'm still confused with maintaining versions: what if the API changes version from 2.1 to 2.2, I would still expect any functionality defined in 2.1 (ie it hasn't changed), to still be handled by 2.2 requests eg:

api_version(:module => "V21", :header => {:name => "API-VERSION", :value => "2.1"}) do
  resources :users, only: [:create]
end
api_version(:module => "V22", :header => {:name => "API-VERSION", :value => "2.2"}) do
  resources :accounts, only: [:create]
end

So accounts have changed in 2.2, but users did not, yet I still want to use 2.1's version and obviously any 2.1 requests would still be captured with that route but not by the 2.2 route. Is this scenario valid or am I confusing things?

bploetz commented 11 years ago

You basically have two choices: completely copy all of the code from V21 to V22, or use inheritance where V22 inherits from V21, and you only override the things that have changed in V22.

Obviously copying is not DRY, but ensures that changes to V22 don't accidentally break something in V21 (yes you should have test coverage for this). It's a balancing act. Only you can decide what's the best method for your API.

HTH