-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #403 from politician/feature/support-accept-versio…
…n-header add support for versioning using the 'Accept-Version' header
- Loading branch information
Showing
9 changed files
with
239 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
require 'grape/middleware/base' | ||
|
||
module Grape | ||
module Middleware | ||
module Versioner | ||
# This middleware sets various version related rack environment variables | ||
# based on the HTTP Accept-Version header | ||
# | ||
# Example: For request header | ||
# Accept-Version: v1 | ||
# | ||
# The following rack env variables are set: | ||
# | ||
# env['api.version] => 'v1' | ||
# | ||
# If version does not match this route, then a 406 is raised with | ||
# X-Cascade header to alert Rack::Mount to attempt the next matched | ||
# route. | ||
class AcceptVersionHeader < Base | ||
|
||
def before | ||
potential_version = (env['HTTP_ACCEPT_VERSION'] || '').strip | ||
|
||
if strict? | ||
# If no Accept-Version header: | ||
if potential_version.empty? | ||
throw :error, :status => 406, :headers => error_headers, :message => 'Accept-Version header must be set.' | ||
end | ||
end | ||
|
||
unless potential_version.empty? | ||
# If the requested version is not supported: | ||
if !versions.any? { |v| v.to_s == potential_version } | ||
throw :error, :status => 406, :headers => error_headers, :message => 'The requested version is not supported.' | ||
end | ||
|
||
env['api.version'] = potential_version | ||
end | ||
end | ||
|
||
private | ||
|
||
def versions | ||
options[:versions] || [] | ||
end | ||
|
||
def strict? | ||
options[:version_options] && options[:version_options][:strict] | ||
end | ||
|
||
# By default those errors contain an `X-Cascade` header set to `pass`, which allows nesting and stacking | ||
# of routes (see [Rack::Mount](https://github.com/josh/rack-mount) for more information). To prevent | ||
# this behavior, and not add the `X-Cascade` header, one can set the `:cascade` option to `false`. | ||
def cascade? | ||
options[:version_options] && options[:version_options].has_key?(:cascade) ? | ||
!! options[:version_options][:cascade] : | ||
true | ||
end | ||
|
||
def error_headers | ||
cascade? ? { 'X-Cascade' => 'pass' } : {} | ||
end | ||
|
||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
121 changes: 121 additions & 0 deletions
121
spec/grape/middleware/versioner/accept_version_header_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
require 'spec_helper' | ||
|
||
describe Grape::Middleware::Versioner::AcceptVersionHeader do | ||
let(:app) { lambda{|env| [200, env, env]} } | ||
subject { Grape::Middleware::Versioner::AcceptVersionHeader.new(app, @options || {}) } | ||
|
||
before do | ||
@options = { | ||
:version_options => { | ||
:using => :accept_version_header | ||
}, | ||
} | ||
end | ||
|
||
context 'api.version' do | ||
before do | ||
@options[:versions] = ['v1'] | ||
end | ||
|
||
it 'is set' do | ||
status, _, env = subject.call('HTTP_ACCEPT_VERSION' => 'v1') | ||
env['api.version'].should eql 'v1' | ||
status.should == 200 | ||
end | ||
|
||
it 'is set if format provided' do | ||
status, _, env = subject.call('HTTP_ACCEPT_VERSION' => 'v1') | ||
env['api.version'].should eql 'v1' | ||
status.should == 200 | ||
end | ||
|
||
it 'fails with 406 Not Acceptable if version is not supported' do | ||
expect { | ||
env = subject.call('HTTP_ACCEPT_VERSION' => 'v2').last | ||
}.to throw_symbol( | ||
:error, | ||
:status => 406, | ||
:headers => {'X-Cascade' => 'pass'}, | ||
:message => 'The requested version is not supported.' | ||
) | ||
end | ||
end | ||
|
||
it 'succeeds if :strict is not set' do | ||
subject.call('HTTP_ACCEPT_VERSION' => '').first.should == 200 | ||
subject.call({}).first.should == 200 | ||
end | ||
|
||
it 'succeeds if :strict is set to false' do | ||
@options[:version_options][:strict] = false | ||
subject.call('HTTP_ACCEPT_VERSION' => '').first.should == 200 | ||
subject.call({}).first.should == 200 | ||
end | ||
|
||
context 'when :strict is set' do | ||
before do | ||
@options[:versions] = ['v1'] | ||
@options[:version_options][:strict] = true | ||
end | ||
|
||
it 'fails with 406 Not Acceptable if header is not set' do | ||
expect { | ||
env = subject.call({}).last | ||
}.to throw_symbol( | ||
:error, | ||
:status => 406, | ||
:headers => {'X-Cascade' => 'pass'}, | ||
:message => 'Accept-Version header must be set.' | ||
) | ||
end | ||
|
||
it 'fails with 406 Not Acceptable if header is empty' do | ||
expect { | ||
env = subject.call('HTTP_ACCEPT_VERSION' => '').last | ||
}.to throw_symbol( | ||
:error, | ||
:status => 406, | ||
:headers => {'X-Cascade' => 'pass'}, | ||
:message => 'Accept-Version header must be set.' | ||
) | ||
end | ||
|
||
it 'succeeds if proper header is set' do | ||
subject.call('HTTP_ACCEPT_VERSION' => 'v1').first.should == 200 | ||
end | ||
end | ||
|
||
context 'when :strict and :cascade=>false are set' do | ||
before do | ||
@options[:versions] = ['v1'] | ||
@options[:version_options][:strict] = true | ||
@options[:version_options][:cascade] = false | ||
end | ||
|
||
it 'fails with 406 Not Acceptable if header is not set' do | ||
expect { | ||
env = subject.call({}).last | ||
}.to throw_symbol( | ||
:error, | ||
:status => 406, | ||
:headers => {}, | ||
:message => 'Accept-Version header must be set.' | ||
) | ||
end | ||
|
||
it 'fails with 406 Not Acceptable if header is empty' do | ||
expect { | ||
env = subject.call('HTTP_ACCEPT_VERSION' => '').last | ||
}.to throw_symbol( | ||
:error, | ||
:status => 406, | ||
:headers => {}, | ||
:message => 'Accept-Version header must be set.' | ||
) | ||
end | ||
|
||
it 'succeeds if proper header is set' do | ||
subject.call('HTTP_ACCEPT_VERSION' => 'v1').first.should == 200 | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters