README.md in versioncake-1.3.0 vs README.md in versioncake-2.0.0

- old
+ new

@@ -12,14 +12,14 @@ - Easily version any view with their API version: ```ruby app/views/posts/ - - index.v1.xml.builder - - index.v3.xml.builder - - index.v1.json.jbuilder - - index.v4.json.jbuilder + - index.xml.v1.builder + - index.xml.v3.builder + - index.json.v1.jbuilder + - index.json.v4.jbuilder ``` - Gracefully degrade requests to the latest supported version - Clients can request API versions through different strategies - Dry your controller logic with exposed helpers @@ -31,20 +31,48 @@ gem install versioncake ``` ### Requirements -Rails >= v3.2 is supported in versioncake =< v1.1. Rails 4 support is included versioncake >= v1.2. +| Version | Rails 3.2 Support? | Rails 4 Support? | Rails 4.1 Support? | +| ------- |:---------:| -------:| -------:| +| 1.0 | Yes | No | No | +| 1.1 | Yes | No | No | +| 1.2 | Yes | Yes | No | +| 1.3 | Yes | Yes | No | +| 2.0 | Yes | Yes | Yes | +## Upgrade v1.0 -> v2.0 + +### Filename changes +The major breaking change to require a bump to v2.0 was the order of the extensions. To avoid priority issues with the format (#14), the version number and the format have been swapped. + +`index.v1.json.jbuilder` -> `index.json.v1.jbuilder` + +To make it easier to upgrade, run the following command to automatically rename these files: + +`verisoncake migrate` or `verisoncake migrate path/to/views` + +### Configuration changes + +The configuration options for Version Cake have been namespaced and slightly renamed. The following is a mapping of the old names to the new names: + +| Old Name | New Name | +| --------------------------------------- | -------------------------------------------- | +| config.view_versions | config.versioncake.supported_version_numbers | +| config.view_version_extraction_strategy | config.versioncake.extraction_strategy | +| config.view_version_string | config.versioncake.version_key | +| config.default_version | config.versioncake.default_version | + ## Example In this simple example we will outline the code that is introduced to support a change in a version. ### config/application.rb ```ruby -config.view_versions = (1...4) -config.view_version_extraction_strategy = :query_parameter # for simplicity +config.versioncake.supported_version_numbers = (1...4) +config.versioncake.extraction_strategy = :query_parameter # for simplicity ``` Often times with APIs, depending upon the version, different logic needs to be applied. With the following controller code, the initial value of @posts includes all Post entries. But if the requested API version is three or greater, we're going to eagerly load the associated comments as well. @@ -63,35 +91,35 @@ end end end ``` -See the view samples below. The basic top level posts are referenced in views/posts/index.v1.json.jbuilder. -But for views/posts/index.v4.json.jbuilder, we utilize the additional related comments. +See the view samples below. The basic top level posts are referenced in views/posts/index.json.v1.jbuilder. +But for views/posts/index.json.v4.jbuilder, we utilize the additional related comments. ### Views Notice the version numbers are denoted by the "v{version number}" extension within the file name. -#### views/posts/index.v1.json.jbuilder +#### views/posts/index.json.v1.jbuilder ```ruby json.array!(@posts) do |json, post| json.(post, :id, :title) end ``` -#### views/posts/index.v4.json.jbuilder +#### views/posts/index.json.v4.jbuilder ```ruby json.array!(@posts) do |json, post| json.(post, :id, :title) json.comments post.comments, :id, :text end ``` ### Sample Output -When a version is specified for which a view doesn't exist, the request degrades and renders the next lowest version number to ensure the API's backwards compatibility. In the following case, since views/posts/index.v3.json.jbuilder doesn't exist, views/posts/index.v1.json.jbuilder is rendered instead. +When a version is specified for which a view doesn't exist, the request degrades and renders the next lowest version number to ensure the API's backwards compatibility. In the following case, since views/posts/index.json.v3.jbuilder doesn't exist, views/posts/index.json.v1.jbuilder is rendered instead. #### http://localhost:3000/posts.json?api_version=3 ```javascript [ { @@ -108,11 +136,11 @@ } ] ``` -For a given request, if we specify the version number, and that version of the view exists, that version specific view version will be rendered. In the below case, views/posts/index.v1.json.jbuilder is rendered. +For a given request, if we specify the version number, and that version of the view exists, that version specific view version will be rendered. In the below case, views/posts/index.json.v1.jbuilder is rendered. #### http://localhost:3000/posts.json?api_version=2 or http://localhost:3000/posts.json?api_version=1 ```javascript [ { @@ -129,11 +157,11 @@ } ] ``` -When no version is specified, the latest version of the view is rendered. In this case, views/posts/index.v4.json.jbuilder. +When no version is specified, the latest version of the view is rendered. In this case, views/posts/index.json.v4.jbuilder. #### http://localhost:3000/posts.json ```javascript [ { @@ -170,39 +198,43 @@ #### Supported Versions You need to define the supported versions in your Rails application.rb file as `view_versions`. Use this config to set the range of supported API versions that can be served: ```ruby -config.view_versions = [1,2,3,4,5] # or (1..5) +config.versioncake.supported_version_numbers = [1,2,3,4,5] # or (1..5) ``` #### Extraction Strategy You can also define the way to extract the version. The `view_version_extraction_strategy` allows you to set one of the default strategies or provide a proc to set your own. You can also pass it a prioritized array of the strategies. ```ruby -config.view_version_extraction_strategy = :query_parameter # [:http_header, :http_accept_parameter] +config.versioncake.extraction_strategy = :query_parameter # [:http_header, :http_accept_parameter] ``` These are the available strategies: - - **query_parameter**: version in the url query parameter, for testing or to override for special case i.e. ```http://localhost:3000/posts.json?api_version=1``` (This is the default.) - - **request_parameter**: version that is sent in the body of the request. Good for testing. - - **http_header**: Api version HTTP header ie. ```X-API-Version: 1``` - - **http_accept_parameter**: HTTP Accept header ie. ```Accept: application/xml; version=1``` [why do this?](http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http#i_want_my_api_to_be_versioned) - - **custom**: `lambda {|request| request.headers["HTTP_X_MY_VERSION"].to_i }` takes the request object and must return an integer +Strategy | Description | Example +--- | --- | --- +:query_parameter | version in the url query parameter, for testing or to override for special case | `http://localhost:3000/posts.json?api_version=1` (This is the default.) +:path_parameter | version in the url path parameter | `api/v:api_version/` +request_parameter | version that is sent in the body of the request | Good for testing. +:http_header | Api version HTTP header | `X-API-Version: 1` +:http_accept_parameter | HTTP Accept header | `Accept: application/xml; version=1` [why do this?](http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http#i_want_my_api_to_be_versioned) +custom | takes the request object and must return an integer | lambda {&#124;request&#124; request.headers["HTTP_X_MY_VERSION"].to_i } + #### Default Version When no version is supplied by a client, the version rendered will be the latest version by default. If you want to override this to another version, set the following property: ```ruby -config.default_version = 4 +config.versioncake.default_version = 4 ``` #### Version String The extraction strategies use a default string key of `api_version`, but that can be changed: ```ruby -config.view_version_string = "special_version_parameter_name" +config.versioncake.version_key = "special_version_parameter_name" ``` ### Version your views When a client makes a request to your controller the latest version of the view will be rendered. The latest version is determined by naming the template or partial with a version number that you configured to support. @@ -211,12 +243,12 @@ - app/views/posts - index.html.erb - edit.html.erb - show.html.erb - show.json.jbuilder - - show.v1.json.jbuilder - - show.v2.json.jbuilder + - show.json.v1.jbuilder + - show.json.v2.jbuilder - new.html.erb - _form.html.erb ``` If you start supporting a newer version, v3 for instance, you do not have to copy posts/show.v2 to posts/show.v3. By default, the request for v3 or higher will gracefully degrade to the view that is the newest, supported version, in this case posts/show.v2. @@ -246,11 +278,11 @@ ### Test configuration Allowing more extraction strategies during testing can be helpful when needing to override the version. ```ruby # config/environments/test.rb -config.view_version_extraction_strategy = [:query_parameter, :request_parameter, :http_header, :http_accept_parameter] +config.versioncake.extraction_strategy = [:query_parameter, :request_parameter, :http_header, :http_accept_parameter] ``` ### Testing a specific version One way to test a specific version for would be to stub the requested version in the before block: @@ -263,27 +295,27 @@ You can also test a specific version through a specific strategy such query_parameter or request_parameter strategies (configured in test environment) like so: ```ruby # test/functional/renders_controller_test.rb#L47 test "render version 1 of the partial based on the parameter _api_version" do get :index, "api_version" => "1" - assert_equal @response.body, "index.v1.html.erb" + assert_equal @response.body, "index.html.v1.erb" end ``` ### Testing all supported versions -You can iterate over all of the supported version numbers by accessing the ```AppName::Application.config.view_versions```. +You can iterate over all of the supported version numbers by accessing the ```AppName::Application.config.versioncake.supported_version_numbers```. ```ruby -AppName::Application.config.view_versions.each do |supported_version| +AppName::Application.config.versioncake.supported_version_numbers.each do |supported_version| before do @controller.stubs(:requested_version).returns(supported_version) end test "all versions render the correct template" do get :index - assert_equal @response.body, "index.v1.html.erb" + assert_equal @response.body, "index.html.v1.erb" end end ``` # Thanks! @@ -294,9 +326,12 @@ * [Alicia](https://github.com/alicial) * [Rohit](https://github.com/rg) * Sevag * [Billy](https://github.com/bcatherall) * [Jérémie Meyer de Ville](https://github.com/jeremiemv) +* [Michael Elfassy](https://github.com/elfassy) +* [Kelley Reynolds](https://github.com/kreynolds) +* [Washington L Braga Jr](https://github.com/huoxito) # Related Material ## Usages