rack-rest_api_versioning 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.rdoc ADDED
@@ -0,0 +1,41 @@
1
+ = Rack REST API Versioning
2
+
3
+ This Rack middleware adds support for RESTful API versioning. According to RESTful best
4
+ practices, the API version should be specified using content negotiation and custom vendor
5
+ MIME types. For example, if your application's API supports multiple versions, a client can
6
+ ask for a specific version like this:
7
+
8
+ GET /foo HTTP/1.1
9
+ Accept: application/vnd.foo.bar-v2+xml
10
+
11
+ Where "application/vnd.foo.bar-v2+xml" is vendor MIME type your application defines.
12
+
13
+ See this article: http://barelyenough.org/blog/2008/05/versioning-rest-web-services/ for more
14
+ information about this practice.
15
+
16
+ This middleware is used like any other rack middleware:
17
+
18
+ use Rack::RestApiVersioning
19
+
20
+ When used, it extracts the version from the Accept header, and makes it available in the
21
+ Rack environment hash as "api_version":
22
+
23
+ app = lambda { |env
24
+ puts env['api_version']
25
+ [200, {}, []]
26
+ }
27
+
28
+ To simplify testing and debugging, this middleware also allows the version to be overriden
29
+ using simple query string parameter:
30
+
31
+ GET /foo?version=2 HTTP/1.1
32
+
33
+ This will ask for version 2, no matter what the Accept header is set to.
34
+
35
+ Finally, a default version can be specified. This will be used if no version can be extracted:
36
+
37
+ use Rack::RestApiVersioning, :default_version => '2.0'
38
+
39
+ == Legal
40
+
41
+ Copyright (c) 2010 Adam Cigánek <adam.ciganek@gmail.com>. Released under the terms of MIT License: www.opensource.org/licenses/mit-license.php
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+
6
+ desc 'Default: run unit tests.'
7
+ task :default => :test
8
+
9
+ desc 'Run unit tests.'
10
+ Rake::TestTask.new(:test) do |t|
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ begin
16
+ require 'jeweler'
17
+
18
+ Jeweler::Tasks.new do |gemspec|
19
+ gemspec.name = 'rack-rest_api_versioning'
20
+ gemspec.summary = 'A Rack middleware to support "the proper way" to version a RESTful API.'
21
+ gemspec.description = "This midleware allows an application to support multiple versions of a RESTful API following the best RESTful practices to encode the version information in the HTTP request. It's inspired by this article: http://barelyenough.org/blog/2008/05/versioning-rest-web-services/."
22
+
23
+ gemspec.email = 'adam.ciganek@gmail.com'
24
+ gemspec.homepage = 'http://github.com/madadam/rack-rest_api_versioning'
25
+ gemspec.authors = ['Adam Cigánek']
26
+
27
+ gemspec.add_dependency 'rack'
28
+ end
29
+
30
+ Jeweler::GemcutterTasks.new
31
+ rescue LoadError
32
+ puts "Jeweler not available. Install it with: gem install jeweler"
33
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,38 @@
1
+ require 'rack'
2
+
3
+ module Rack
4
+ class RestApiVersioning
5
+ def initialize(app, options = {})
6
+ @app = app
7
+ @options = options
8
+ end
9
+
10
+ def call(env)
11
+ extract_version!(env)
12
+ @app.call(env)
13
+ end
14
+
15
+ # 1
16
+ # 1.2
17
+ # 1.2.3
18
+ VERSION_STRING = '(\d+(?:\.\d+)*)'
19
+
20
+ # application/vnd.foo.bar-v1+xml
21
+ # application/vnd.foo.bar-v1.2.3+json
22
+ # ...
23
+ HTTP_ACCEPT_PATTERN = /.*\-v#{VERSION_STRING}/
24
+
25
+ # ?version=1.2.3
26
+ QUERY_STRING_PATTERN = /\bversion=#{VERSION_STRING}/
27
+
28
+ private
29
+
30
+ def extract_version!(env)
31
+ version = env['QUERY_STRING'].to_s[QUERY_STRING_PATTERN, 1] ||
32
+ env['HTTP_ACCEPT'].to_s[HTTP_ACCEPT_PATTERN, 1] ||
33
+ @options[:default_version]
34
+
35
+ env['api_version'] = version
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,67 @@
1
+ require 'test/unit'
2
+ require 'rack'
3
+ require 'rack/test'
4
+
5
+ require 'rack/rest_api_versioning'
6
+
7
+ class RestApiVersioningTest < Test::Unit::TestCase
8
+ include Rack::Test::Methods
9
+
10
+ def app
11
+ @app
12
+ end
13
+
14
+ def test_extracts_version_from_content_type
15
+ app! { use Rack::RestApiVersioning }
16
+
17
+ get '/', {}, 'HTTP_ACCEPT' => 'application/vnd.acme-v1+json'
18
+ assert_equal '1', last_request.env['api_version']
19
+
20
+ get '/', {}, 'HTTP_ACCEPT' => 'application/vnd.acme-v2+json'
21
+ assert_equal '2', last_request.env['api_version']
22
+
23
+ get '/', {}, 'HTTP_ACCEPT' => 'application/vnd.acme-v1.2.3+json'
24
+ assert_equal '1.2.3', last_request.env['api_version']
25
+ end
26
+
27
+ def test_fallbacks_to_default_version_if_no_version_can_be_extracted
28
+ app! { use Rack::RestApiVersioning, :default_version => '4.5' }
29
+
30
+ get '/', {}, 'HTTP_ACCEPT' => 'application/vnd.acme+json'
31
+ assert_equal '4.5', last_request.env['api_version']
32
+
33
+ get '/', {}, 'HTTP_ACCEPT' => 'application/json'
34
+ assert_equal '4.5', last_request.env['api_version']
35
+ end
36
+
37
+ def test_does_not_fallback_to_default_version_if_version_can_be_extracted
38
+ app! { use Rack::RestApiVersioning, :default_version => '6.7' }
39
+
40
+ get '/', {}, 'HTTP_ACCEPT' => 'application/vnd.acme-v2+json'
41
+ assert_equal '2', last_request.env['api_version']
42
+ end
43
+
44
+ def test_allows_version_to_be_overriden_with_query_string_parameter
45
+ app! { use Rack::RestApiVersioning }
46
+
47
+ get '/', 'version' => '1.2'
48
+ assert_equal '1.2', last_request.env['api_version']
49
+ end
50
+
51
+ def test_version_in_query_string_takes_precedence_over_version_in_content_type
52
+ app! { use Rack::RestApiVersioning }
53
+
54
+ get '/', 'version' => '1.2', 'HTTP_ACCEPT' => 'application/vnd.acme-v1.3'
55
+ assert_equal '1.2', last_request.env['api_version']
56
+ end
57
+
58
+ private
59
+
60
+ def app!(&block)
61
+ @app = Rack::Builder.new do
62
+ instance_eval(&block)
63
+ run lambda { |env| [200, {}, []] }
64
+ end.to_app
65
+ end
66
+ end
67
+
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-rest_api_versioning
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - "Adam Cig\xC3\xA1nek"
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-06-08 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rack
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
+ description: "This midleware allows an application to support multiple versions of a RESTful API following the best RESTful practices to encode the version information in the HTTP request. It's inspired by this article: http://barelyenough.org/blog/2008/05/versioning-rest-web-services/."
33
+ email: adam.ciganek@gmail.com
34
+ executables: []
35
+
36
+ extensions: []
37
+
38
+ extra_rdoc_files:
39
+ - README.rdoc
40
+ files:
41
+ - README.rdoc
42
+ - Rakefile
43
+ - VERSION
44
+ - lib/rack/rest_api_versioning.rb
45
+ - test/rest_api_versioning_test.rb
46
+ has_rdoc: true
47
+ homepage: http://github.com/madadam/rack-rest_api_versioning
48
+ licenses: []
49
+
50
+ post_install_message:
51
+ rdoc_options:
52
+ - --charset=UTF-8
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ segments:
67
+ - 0
68
+ version: "0"
69
+ requirements: []
70
+
71
+ rubyforge_project:
72
+ rubygems_version: 1.3.6
73
+ signing_key:
74
+ specification_version: 3
75
+ summary: A Rack middleware to support "the proper way" to version a RESTful API.
76
+ test_files:
77
+ - test/rest_api_versioning_test.rb