Skip to content

Commit f7728b8

Browse files
author
Michael Bleigh
committed
Adds accept header detection to formatter.
1 parent a3b57f9 commit f7728b8

File tree

6 files changed

+80
-11
lines changed

6 files changed

+80
-11
lines changed

Gemfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ group :development do
1010
end
1111

1212
group :test do
13-
gem 'rspec', '>= 2.0.0.beta.19'
13+
gem 'rspec', '>= 2.0.0.beta.20'
1414
gem 'rack-test'
1515
gem 'cucumber', '>= 0.8.5'
1616
end

Gemfile.lock

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ GEM
2525
rack-test (0.5.4)
2626
rack (>= 1.0)
2727
rake (0.8.7)
28-
rspec (2.0.0.beta.19)
29-
rspec-core (= 2.0.0.beta.19)
30-
rspec-expectations (= 2.0.0.beta.19)
31-
rspec-mocks (= 2.0.0.beta.19)
32-
rspec-core (2.0.0.beta.19)
33-
rspec-expectations (2.0.0.beta.19)
28+
rspec (2.0.0.beta.20)
29+
rspec-core (= 2.0.0.beta.20)
30+
rspec-expectations (= 2.0.0.beta.20)
31+
rspec-mocks (= 2.0.0.beta.20)
32+
rspec-core (2.0.0.beta.20)
33+
rspec-expectations (2.0.0.beta.20)
3434
diff-lcs (>= 1.1.2)
35-
rspec-mocks (2.0.0.beta.19)
35+
rspec-mocks (2.0.0.beta.20)
3636
rubyforge (2.0.4)
3737
json_pure (>= 1.1.7)
3838
term-ansicolor (1.0.5)
@@ -50,4 +50,4 @@ DEPENDENCIES
5050
rack-mount
5151
rack-test
5252
rake
53-
rspec (>= 2.0.0.beta.19)
53+
rspec (>= 2.0.0.beta.20)

lib/grape/middleware/formatter.rb

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,17 @@ def content_types
2222
CONTENT_TYPES.merge(options[:content_types])
2323
end
2424

25+
def mime_types
26+
CONTENT_TYPES.invert
27+
end
28+
29+
def headers
30+
env.dup.inject({}){|h,(k,v)| h[k.downcase] = v; h}
31+
end
32+
2533
def before
2634
fmt = format_from_extension || format_from_header || options[:default_format]
27-
35+
2836
if content_types.key?(fmt)
2937
env['api.format'] = fmt
3038
else
@@ -44,7 +52,24 @@ def format_from_extension
4452
end
4553

4654
def format_from_header
47-
# TODO: Implement Accept header parsing.
55+
mime_array.each do |t|
56+
if mime_types.key?(t)
57+
return mime_types[t]
58+
end
59+
end
60+
nil
61+
end
62+
63+
def mime_array
64+
accept = headers['accept']
65+
if accept
66+
accept.gsub(/\b/,'').
67+
scan(/(\w+\/[\w+]+)(?:;[^,]*q=([0-9.]+)[^,]*)?/i).
68+
sort_by{|a| -a[1].to_f}.
69+
map{|a| a[0]}
70+
else
71+
[]
72+
end
4873
end
4974

5075
def after

lib/grape/middleware/versioner.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ def before
1313
pieces = env['PATH_INFO'].split('/')
1414
potential_version = pieces[1]
1515
if potential_version =~ options[:pattern]
16+
if options[:versions] && !options[:versions].include?(potential_version)
17+
throw :error, :status => 404, :message => "The specified version of the API does not exist."
18+
end
19+
1620
truncated_path = "/#{pieces[2..-1].join('/')}"
1721
env['api.version'] = potential_version
1822
env['PATH_INFO'] = truncated_path

spec/grape/middleware/formatter_spec.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,33 @@
3232
err.should == {:status => 406, :message => "The requested format is not supported."}
3333
end
3434
end
35+
36+
context 'Accept header detection' do
37+
it 'should detect from the Accept header' do
38+
subject.call({'PATH_INFO' => '/info', 'Accept' => 'application/xml'})
39+
subject.env['api.format'].should == :xml
40+
end
41+
42+
it 'should look for case-indifferent headers' do
43+
subject.call({'PATH_INFO' => '/info', 'accept' => 'application/xml'})
44+
subject.env['api.format'].should == :xml
45+
end
46+
47+
it 'should use quality rankings to determine formats' do
48+
subject.call({'PATH_INFO' => '/info', 'Accept' => 'application/json; q=0.3,application/xml; q=1.0'})
49+
subject.env['api.format'].should == :xml
50+
subject.call({'PATH_INFO' => '/info', 'Accept' => 'application/json; q=1.0,application/xml; q=0.3'})
51+
subject.env['api.format'].should == :json
52+
end
53+
54+
it 'should handle quality rankings mixed with nothing' do
55+
subject.call({'PATH_INFO' => '/info', 'Accept' => 'application/json,application/xml; q=1.0'})
56+
subject.env['api.format'].should == :xml
57+
end
58+
59+
it 'should properly parse headers with other attributes' do
60+
subject.call({'PATH_INFO' => '/info', 'Accept' => 'application/json; abc=2.3; q=1.0,application/xml; q=0.7'})
61+
subject.env['api.format'].should == :json
62+
end
63+
end
3564
end

spec/grape/middleware/versioner_spec.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,15 @@
2626
subject.call('PATH_INFO' => '/awesome/radical').last.should be_nil
2727
end
2828
end
29+
30+
context 'with specified versions' do
31+
before{ @options = {:versions => ['v1', 'v2']}}
32+
it 'should throw an error if a non-allowed version is specified' do
33+
catch(:error){subject.call('PATH_INFO' => '/v3/awesome')}[:status].should == 404
34+
end
35+
36+
it 'should allow versions that have been specified' do
37+
subject.call('PATH_INFO' => '/v1/asoasd').last.should == 'v1'
38+
end
39+
end
2940
end

0 commit comments

Comments
 (0)