grape 0.2.3 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of grape might be problematic. Click here for more details.
- data/.yardopts +2 -0
- data/CHANGELOG.markdown +19 -0
- data/Gemfile +2 -0
- data/README.markdown +166 -131
- data/Rakefile +1 -3
- data/lib/grape.rb +0 -3
- data/lib/grape/api.rb +16 -4
- data/lib/grape/cookies.rb +32 -30
- data/lib/grape/endpoint.rb +25 -11
- data/lib/grape/entity.rb +5 -0
- data/lib/grape/error_formatter/base.rb +2 -1
- data/lib/grape/middleware/base.rb +9 -2
- data/lib/grape/middleware/error.rb +11 -11
- data/lib/grape/middleware/formatter.rb +8 -5
- data/lib/grape/middleware/versioner/header.rb +1 -3
- data/lib/grape/middleware/versioner/path.rb +15 -2
- data/lib/grape/util/deep_merge.rb +4 -4
- data/lib/grape/validations.rb +2 -3
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api_spec.rb +316 -175
- data/spec/grape/endpoint_spec.rb +159 -57
- data/spec/grape/entity_spec.rb +80 -80
- data/spec/grape/middleware/auth/basic_spec.rb +3 -3
- data/spec/grape/middleware/auth/digest_spec.rb +4 -4
- data/spec/grape/middleware/auth/oauth2_spec.rb +4 -4
- data/spec/grape/middleware/base_spec.rb +9 -9
- data/spec/grape/middleware/error_spec.rb +4 -4
- data/spec/grape/middleware/exception_spec.rb +13 -13
- data/spec/grape/middleware/formatter_spec.rb +25 -25
- data/spec/grape/middleware/versioner/header_spec.rb +23 -23
- data/spec/grape/middleware/versioner/param_spec.rb +8 -8
- data/spec/grape/middleware/versioner/path_spec.rb +8 -8
- data/spec/grape/middleware/versioner_spec.rb +6 -3
- data/spec/grape/util/hash_stack_spec.rb +20 -20
- data/spec/grape/validations/presence_spec.rb +1 -1
- data/spec/grape/validations/regexp_spec.rb +2 -2
- data/spec/grape/validations_spec.rb +4 -4
- data/spec/shared/versioning_examples.rb +48 -20
- metadata +5 -7
- data/.document +0 -5
- data/lib/grape/middleware/prefixer.rb +0 -21
- data/spec/grape/middleware/prefixer_spec.rb +0 -30
@@ -13,18 +13,18 @@ describe Grape::Middleware::Auth::Basic do
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
it '
|
16
|
+
it 'throws a 401 if no auth is given' do
|
17
17
|
@proc = lambda{ false }
|
18
18
|
get '/whatever'
|
19
19
|
last_response.status.should == 401
|
20
20
|
end
|
21
21
|
|
22
|
-
it '
|
22
|
+
it 'authenticates if given valid creds' do
|
23
23
|
get '/whatever', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('admin','admin')
|
24
24
|
last_response.status.should == 200
|
25
25
|
end
|
26
26
|
|
27
|
-
it '
|
27
|
+
it 'throws a 401 is wrong auth is given' do
|
28
28
|
get '/whatever', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('admin','wrong')
|
29
29
|
last_response.status.should == 401
|
30
30
|
end
|
@@ -23,23 +23,23 @@ describe Grape::Middleware::Auth::Digest do
|
|
23
23
|
Test
|
24
24
|
end
|
25
25
|
|
26
|
-
it '
|
26
|
+
it 'is a digest authentication challenge' do
|
27
27
|
get '/test'
|
28
28
|
last_response.should be_challenge
|
29
29
|
end
|
30
30
|
|
31
|
-
it '
|
31
|
+
it 'throws a 401 if no auth is given' do
|
32
32
|
get '/test'
|
33
33
|
last_response.status.should == 401
|
34
34
|
end
|
35
35
|
|
36
|
-
it '
|
36
|
+
it 'authenticates if given valid creds' do
|
37
37
|
digest_authorize "foo", "bar"
|
38
38
|
get '/test'
|
39
39
|
last_response.status.should == 200
|
40
40
|
end
|
41
41
|
|
42
|
-
it '
|
42
|
+
it 'throws a 401 if given invalid creds' do
|
43
43
|
digest_authorize "bar", "foo"
|
44
44
|
get '/test'
|
45
45
|
last_response.status.should == 401
|
@@ -32,7 +32,7 @@ describe Grape::Middleware::Auth::OAuth2 do
|
|
32
32
|
context 'and a valid token' do
|
33
33
|
before { get '/awesome?oauth_token=g123' }
|
34
34
|
|
35
|
-
it '
|
35
|
+
it 'sets env["api.token"]' do
|
36
36
|
last_response.body.should == 'g123'
|
37
37
|
end
|
38
38
|
end
|
@@ -44,11 +44,11 @@ describe Grape::Middleware::Auth::OAuth2 do
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
it '
|
47
|
+
it 'throws an error' do
|
48
48
|
@err[:status].should == 401
|
49
49
|
end
|
50
50
|
|
51
|
-
it '
|
51
|
+
it 'sets the WWW-Authenticate header in the response' do
|
52
52
|
@err[:headers]['WWW-Authenticate'].should == "OAuth realm='OAuth API', error='invalid_token'"
|
53
53
|
end
|
54
54
|
end
|
@@ -66,7 +66,7 @@ describe Grape::Middleware::Auth::OAuth2 do
|
|
66
66
|
end
|
67
67
|
|
68
68
|
%w(HTTP_AUTHORIZATION X_HTTP_AUTHORIZATION X-HTTP_AUTHORIZATION REDIRECT_X_HTTP_AUTHORIZATION).each do |head|
|
69
|
-
context
|
69
|
+
context 'with the token in the #{head} header' do
|
70
70
|
before { get '/awesome', {}, head => 'OAuth g123' }
|
71
71
|
it { last_response.body.should == 'g123' }
|
72
72
|
end
|
@@ -9,38 +9,38 @@ describe Grape::Middleware::Base do
|
|
9
9
|
subject.stub!(:dup).and_return(subject)
|
10
10
|
end
|
11
11
|
|
12
|
-
it '
|
12
|
+
it 'has the app as an accessor' do
|
13
13
|
subject.app.should == blank_app
|
14
14
|
end
|
15
15
|
|
16
|
-
it '
|
16
|
+
it 'is able to access the request' do
|
17
17
|
subject.call({})
|
18
18
|
subject.request.should be_kind_of(Rack::Request)
|
19
19
|
end
|
20
20
|
|
21
|
-
it '
|
21
|
+
it 'calls through to the app' do
|
22
22
|
subject.call({}).should == [200, {}, 'Hi there.']
|
23
23
|
end
|
24
24
|
|
25
25
|
context 'callbacks' do
|
26
|
-
it '
|
26
|
+
it 'calls #before' do
|
27
27
|
subject.should_receive(:before)
|
28
28
|
end
|
29
29
|
|
30
|
-
it '
|
30
|
+
it 'calls #after' do
|
31
31
|
subject.should_receive(:after)
|
32
32
|
end
|
33
33
|
|
34
34
|
after{ subject.call!({}) }
|
35
35
|
end
|
36
36
|
|
37
|
-
it '
|
37
|
+
it 'is able to access the response' do
|
38
38
|
subject.call({})
|
39
39
|
subject.response.should be_kind_of(Rack::Response)
|
40
40
|
end
|
41
41
|
|
42
42
|
context 'options' do
|
43
|
-
it '
|
43
|
+
it 'persists options passed at initialization' do
|
44
44
|
Grape::Middleware::Base.new(blank_app, {:abc => true}).options[:abc].should be_true
|
45
45
|
end
|
46
46
|
|
@@ -51,11 +51,11 @@ describe Grape::Middleware::Base do
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
it '
|
54
|
+
it 'persists the default options' do
|
55
55
|
ExampleWare.new(blank_app).options[:monkey].should be_true
|
56
56
|
end
|
57
57
|
|
58
|
-
it '
|
58
|
+
it 'overrides default options when provided' do
|
59
59
|
ExampleWare.new(blank_app, :monkey => false).options[:monkey].should be_false
|
60
60
|
end
|
61
61
|
end
|
@@ -19,25 +19,25 @@ describe Grape::Middleware::Error do
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
it '
|
22
|
+
it 'sets the status code appropriately' do
|
23
23
|
ErrApp.error = {:status => 410}
|
24
24
|
get '/'
|
25
25
|
last_response.status.should == 410
|
26
26
|
end
|
27
27
|
|
28
|
-
it '
|
28
|
+
it 'sets the error message appropriately' do
|
29
29
|
ErrApp.error = {:message => 'Awesome stuff.'}
|
30
30
|
get '/'
|
31
31
|
last_response.body.should == 'Awesome stuff.'
|
32
32
|
end
|
33
33
|
|
34
|
-
it '
|
34
|
+
it 'defaults to a 403 status' do
|
35
35
|
ErrApp.error = {}
|
36
36
|
get '/'
|
37
37
|
last_response.status.should == 403
|
38
38
|
end
|
39
39
|
|
40
|
-
it '
|
40
|
+
it 'has a default message' do
|
41
41
|
ErrApp.error = {}
|
42
42
|
get '/'
|
43
43
|
last_response.body.should == 'Aww, hamburgers.'
|
@@ -50,7 +50,7 @@ describe Grape::Middleware::Error do
|
|
50
50
|
@app
|
51
51
|
end
|
52
52
|
|
53
|
-
it '
|
53
|
+
it 'does not trap errors by default' do
|
54
54
|
@app ||= Rack::Builder.app do
|
55
55
|
use Grape::Middleware::Error
|
56
56
|
run ExceptionApp
|
@@ -59,7 +59,7 @@ describe Grape::Middleware::Error do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
context 'with rescue_all set to true' do
|
62
|
-
it '
|
62
|
+
it 'sets the message appropriately' do
|
63
63
|
@app ||= Rack::Builder.app do
|
64
64
|
use Grape::Middleware::Error, :rescue_all => true
|
65
65
|
run ExceptionApp
|
@@ -68,7 +68,7 @@ describe Grape::Middleware::Error do
|
|
68
68
|
last_response.body.should == "rain!"
|
69
69
|
end
|
70
70
|
|
71
|
-
it '
|
71
|
+
it 'defaults to a 403 status' do
|
72
72
|
@app ||= Rack::Builder.app do
|
73
73
|
use Grape::Middleware::Error, :rescue_all => true
|
74
74
|
run ExceptionApp
|
@@ -77,7 +77,7 @@ describe Grape::Middleware::Error do
|
|
77
77
|
last_response.status.should == 403
|
78
78
|
end
|
79
79
|
|
80
|
-
it '
|
80
|
+
it 'is possible to specify a different default status code' do
|
81
81
|
@app ||= Rack::Builder.app do
|
82
82
|
use Grape::Middleware::Error, :rescue_all => true, :default_status => 500
|
83
83
|
run ExceptionApp
|
@@ -86,7 +86,7 @@ describe Grape::Middleware::Error do
|
|
86
86
|
last_response.status.should == 500
|
87
87
|
end
|
88
88
|
|
89
|
-
it '
|
89
|
+
it 'is possible to return errors in json format' do
|
90
90
|
@app ||= Rack::Builder.app do
|
91
91
|
use Grape::Middleware::Error, :rescue_all => true, :format => :json
|
92
92
|
run ExceptionApp
|
@@ -95,17 +95,17 @@ describe Grape::Middleware::Error do
|
|
95
95
|
last_response.body.should == '{"error":"rain!"}'
|
96
96
|
end
|
97
97
|
|
98
|
-
it '
|
98
|
+
it 'is possible to return hash errors in json format' do
|
99
99
|
@app ||= Rack::Builder.app do
|
100
100
|
use Grape::Middleware::Error, :rescue_all => true, :format => :json
|
101
101
|
run ErrorHashApp
|
102
102
|
end
|
103
103
|
get '/'
|
104
104
|
['{"error":"rain!","detail":"missing widget"}',
|
105
|
-
'{"detail":"missing widget","error":"rain!"}'].should
|
105
|
+
'{"detail":"missing widget","error":"rain!"}'].should include(last_response.body)
|
106
106
|
end
|
107
107
|
|
108
|
-
it '
|
108
|
+
it 'is possible to return errors in xml format' do
|
109
109
|
@app ||= Rack::Builder.app do
|
110
110
|
use Grape::Middleware::Error, :rescue_all => true, :format => :xml
|
111
111
|
run ExceptionApp
|
@@ -114,17 +114,17 @@ describe Grape::Middleware::Error do
|
|
114
114
|
last_response.body.should == "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<error>\n <message>rain!</message>\n</error>\n"
|
115
115
|
end
|
116
116
|
|
117
|
-
it '
|
117
|
+
it 'is possible to return hash errors in xml format' do
|
118
118
|
@app ||= Rack::Builder.app do
|
119
119
|
use Grape::Middleware::Error, :rescue_all => true, :format => :xml
|
120
120
|
run ErrorHashApp
|
121
121
|
end
|
122
122
|
get '/'
|
123
123
|
["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<error>\n <detail>missing widget</detail>\n <error>rain!</error>\n</error>\n",
|
124
|
-
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<error>\n <error>rain!</error>\n <detail>missing widget</detail>\n</error>\n"].should
|
124
|
+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<error>\n <error>rain!</error>\n <detail>missing widget</detail>\n</error>\n"].should include(last_response.body)
|
125
125
|
end
|
126
126
|
|
127
|
-
it '
|
127
|
+
it 'is possible to specify a custom formatter' do
|
128
128
|
@app ||= Rack::Builder.app do
|
129
129
|
use Grape::Middleware::Error,
|
130
130
|
:rescue_all => true,
|
@@ -140,7 +140,7 @@ describe Grape::Middleware::Error do
|
|
140
140
|
last_response.body.should == '{:custom_formatter=>"rain!"}'
|
141
141
|
end
|
142
142
|
|
143
|
-
it '
|
143
|
+
it 'does not trap regular error! codes' do
|
144
144
|
@app ||= Rack::Builder.app do
|
145
145
|
use Grape::Middleware::Error
|
146
146
|
run AccessDeniedApp
|
@@ -149,7 +149,7 @@ describe Grape::Middleware::Error do
|
|
149
149
|
last_response.status.should == 401
|
150
150
|
end
|
151
151
|
|
152
|
-
it '
|
152
|
+
it 'responds to custom Grape exceptions appropriately' do
|
153
153
|
@app ||= Rack::Builder.app do
|
154
154
|
use Grape::Middleware::Error, :rescue_all => false
|
155
155
|
run CustomErrorApp
|
@@ -7,13 +7,13 @@ describe Grape::Middleware::Formatter do
|
|
7
7
|
let(:app){ lambda{|env| [200, {}, [@body]]} }
|
8
8
|
|
9
9
|
context 'serialization' do
|
10
|
-
it '
|
10
|
+
it 'looks at the bodies for possibly serializable data' do
|
11
11
|
@body = {"abc" => "def"}
|
12
12
|
status, headers, bodies = *subject.call({'PATH_INFO' => '/somewhere', 'HTTP_ACCEPT' => 'application/json'})
|
13
13
|
bodies.each{|b| b.should == MultiJson.dump(@body) }
|
14
14
|
end
|
15
15
|
|
16
|
-
it '
|
16
|
+
it 'calls #to_json since default format is json' do
|
17
17
|
@body = ['foo']
|
18
18
|
@body.instance_eval do
|
19
19
|
def to_json
|
@@ -24,7 +24,7 @@ describe Grape::Middleware::Formatter do
|
|
24
24
|
subject.call({'PATH_INFO' => '/somewhere', 'HTTP_ACCEPT' => 'application/json'}).last.each{|b| b.should == '"bar"'}
|
25
25
|
end
|
26
26
|
|
27
|
-
it '
|
27
|
+
it 'calls #to_xml if the content type is xml' do
|
28
28
|
@body = "string"
|
29
29
|
@body.instance_eval do
|
30
30
|
def to_xml
|
@@ -37,89 +37,89 @@ describe Grape::Middleware::Formatter do
|
|
37
37
|
end
|
38
38
|
|
39
39
|
context 'detection' do
|
40
|
-
it '
|
40
|
+
it 'uses the extension if one is provided' do
|
41
41
|
subject.call({'PATH_INFO' => '/info.xml'})
|
42
42
|
subject.env['api.format'].should == :xml
|
43
43
|
subject.call({'PATH_INFO' => '/info.json'})
|
44
44
|
subject.env['api.format'].should == :json
|
45
45
|
end
|
46
46
|
|
47
|
-
it '
|
47
|
+
it 'uses the format parameter if one is provided' do
|
48
48
|
subject.call({'PATH_INFO' => '/somewhere','QUERY_STRING' => 'format=json'})
|
49
49
|
subject.env['api.format'].should == :json
|
50
50
|
subject.call({'PATH_INFO' => '/somewhere','QUERY_STRING' => 'format=xml'})
|
51
51
|
subject.env['api.format'].should == :xml
|
52
52
|
end
|
53
53
|
|
54
|
-
it '
|
54
|
+
it 'uses the default format if none is provided' do
|
55
55
|
subject.call({'PATH_INFO' => '/info'})
|
56
56
|
subject.env['api.format'].should == :txt
|
57
57
|
end
|
58
58
|
|
59
|
-
it '
|
59
|
+
it 'uses the requested format if provided in headers' do
|
60
60
|
subject.call({'PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/json'})
|
61
61
|
subject.env['api.format'].should == :json
|
62
62
|
end
|
63
63
|
|
64
|
-
it '
|
64
|
+
it 'uses the file extension format if provided before headers' do
|
65
65
|
subject.call({'PATH_INFO' => '/info.txt', 'HTTP_ACCEPT' => 'application/json'})
|
66
66
|
subject.env['api.format'].should == :txt
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
70
|
context 'Accept header detection' do
|
71
|
-
it '
|
71
|
+
it 'detects from the Accept header' do
|
72
72
|
subject.call({'PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/xml'})
|
73
73
|
subject.env['api.format'].should == :xml
|
74
74
|
end
|
75
75
|
|
76
|
-
it '
|
76
|
+
it 'looks for case-indifferent headers' do
|
77
77
|
subject.call({'PATH_INFO' => '/info', 'http_accept' => 'application/xml'})
|
78
78
|
subject.env['api.format'].should == :xml
|
79
79
|
end
|
80
80
|
|
81
|
-
it '
|
81
|
+
it 'uses quality rankings to determine formats' do
|
82
82
|
subject.call({'PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/json; q=0.3,application/xml; q=1.0'})
|
83
83
|
subject.env['api.format'].should == :xml
|
84
84
|
subject.call({'PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/json; q=1.0,application/xml; q=0.3'})
|
85
85
|
subject.env['api.format'].should == :json
|
86
86
|
end
|
87
87
|
|
88
|
-
it '
|
88
|
+
it 'handles quality rankings mixed with nothing' do
|
89
89
|
subject.call({'PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/json,application/xml; q=1.0'})
|
90
90
|
subject.env['api.format'].should == :xml
|
91
91
|
end
|
92
92
|
|
93
|
-
it '
|
93
|
+
it 'parses headers with other attributes' do
|
94
94
|
subject.call({'PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/json; abc=2.3; q=1.0,application/xml; q=0.7'})
|
95
95
|
subject.env['api.format'].should == :json
|
96
96
|
end
|
97
97
|
|
98
|
-
it '
|
98
|
+
it 'parses headers with vendor and api version' do
|
99
99
|
subject.call({'PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/vnd.test-v1+xml'})
|
100
100
|
subject.env['api.format'].should == :xml
|
101
101
|
end
|
102
102
|
|
103
|
-
it '
|
103
|
+
it 'parses headers with symbols as hash keys' do
|
104
104
|
subject.call({'PATH_INFO' => '/info', 'http_accept' => 'application/xml', :system_time => '091293'})
|
105
105
|
subject.env[:system_time].should == '091293'
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
109
109
|
context 'Content-type' do
|
110
|
-
it '
|
110
|
+
it 'is set for json' do
|
111
111
|
_, headers, _ = subject.call({'PATH_INFO' => '/info.json'})
|
112
112
|
headers['Content-type'].should == 'application/json'
|
113
113
|
end
|
114
|
-
it '
|
114
|
+
it 'is set for xml' do
|
115
115
|
_, headers, _ = subject.call({'PATH_INFO' => '/info.xml'})
|
116
116
|
headers['Content-type'].should == 'application/xml'
|
117
117
|
end
|
118
|
-
it '
|
118
|
+
it 'is set for txt' do
|
119
119
|
_, headers, _ = subject.call({'PATH_INFO' => '/info.txt'})
|
120
120
|
headers['Content-type'].should == 'text/plain'
|
121
121
|
end
|
122
|
-
it '
|
122
|
+
it 'is set for custom' do
|
123
123
|
subject.options[:content_types] = {}
|
124
124
|
subject.options[:content_types][:custom] = 'application/x-custom'
|
125
125
|
_, headers, _ = subject.call({'PATH_INFO' => '/info.custom'})
|
@@ -128,19 +128,19 @@ describe Grape::Middleware::Formatter do
|
|
128
128
|
end
|
129
129
|
|
130
130
|
context 'Format' do
|
131
|
-
it '
|
131
|
+
it 'uses custom formatter' do
|
132
132
|
subject.options[:content_types] = {}
|
133
133
|
subject.options[:content_types][:custom] = "don't care"
|
134
134
|
subject.options[:formatters][:custom] = lambda { |obj, env| 'CUSTOM FORMAT' }
|
135
135
|
_, _, body = subject.call({'PATH_INFO' => '/info.custom'})
|
136
136
|
body.body.should == ['CUSTOM FORMAT']
|
137
137
|
end
|
138
|
-
it '
|
138
|
+
it 'uses default json formatter' do
|
139
139
|
@body = ['blah']
|
140
140
|
_, _, body = subject.call({'PATH_INFO' => '/info.json'})
|
141
141
|
body.body.should == ['["blah"]']
|
142
142
|
end
|
143
|
-
it '
|
143
|
+
it 'uses custom json formatter' do
|
144
144
|
subject.options[:formatters][:json] = lambda { |obj, env| 'CUSTOM JSON FORMAT' }
|
145
145
|
_, _, body = subject.call({'PATH_INFO' => '/info.json'})
|
146
146
|
body.body.should == ['CUSTOM JSON FORMAT']
|
@@ -148,16 +148,16 @@ describe Grape::Middleware::Formatter do
|
|
148
148
|
end
|
149
149
|
|
150
150
|
context 'Input' do
|
151
|
-
it '
|
151
|
+
it 'parses the body from a POST/PUT and put the contents into rack.request.form_hash' do
|
152
152
|
subject.call({'PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/json', 'rack.input' => StringIO.new('{"is_boolean":true,"string":"thing"}')})
|
153
153
|
subject.env['rack.request.form_hash']['is_boolean'].should be_true
|
154
154
|
subject.env['rack.request.form_hash']['string'].should == 'thing'
|
155
155
|
end
|
156
|
-
it '
|
156
|
+
it 'parses the body from an xml POST/PUT and put the contents into rack.request.from_hash' do
|
157
157
|
subject.call({'PATH_INFO' => '/info.xml', 'HTTP_ACCEPT' => 'application/xml', 'rack.input' => StringIO.new('<thing><name>Test</name></thing>')})
|
158
158
|
subject.env['rack.request.form_hash']['thing']['name'].should == 'Test'
|
159
159
|
end
|
160
|
-
it '
|
160
|
+
it 'is able to fail gracefully if the body is regular POST content' do
|
161
161
|
subject.call({'PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/json', 'rack.input' => StringIO.new('name=Other+Test+Thing')})
|
162
162
|
subject.env['rack.request.form_hash'].should be_nil
|
163
163
|
end
|
@@ -14,21 +14,21 @@ describe Grape::Middleware::Versioner::Header do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
context 'api.type and api.subtype' do
|
17
|
-
it '
|
17
|
+
it 'sets type and subtype to first choice of content type if no preference given' do
|
18
18
|
status, _, env = subject.call('HTTP_ACCEPT' => '*/*')
|
19
19
|
env['api.type'].should eql 'application'
|
20
20
|
env['api.subtype'].should eql 'vnd.vendor+xml'
|
21
21
|
status.should == 200
|
22
22
|
end
|
23
23
|
|
24
|
-
it '
|
24
|
+
it 'sets preferred type' do
|
25
25
|
status, _, env = subject.call('HTTP_ACCEPT' => 'application/*')
|
26
26
|
env['api.type'].should eql 'application'
|
27
27
|
env['api.subtype'].should eql 'vnd.vendor+xml'
|
28
28
|
status.should == 200
|
29
29
|
end
|
30
30
|
|
31
|
-
it '
|
31
|
+
it 'sets preferred type and subtype' do
|
32
32
|
status, _, env = subject.call('HTTP_ACCEPT' => 'text/plain')
|
33
33
|
env['api.type'].should eql 'text'
|
34
34
|
env['api.subtype'].should eql 'plain'
|
@@ -37,13 +37,13 @@ describe Grape::Middleware::Versioner::Header do
|
|
37
37
|
end
|
38
38
|
|
39
39
|
context 'api.format' do
|
40
|
-
it '
|
40
|
+
it 'is set' do
|
41
41
|
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor+json')
|
42
42
|
env['api.format'].should eql 'json'
|
43
43
|
status.should == 200
|
44
44
|
end
|
45
45
|
|
46
|
-
it '
|
46
|
+
it 'is nil if not provided' do
|
47
47
|
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor')
|
48
48
|
env['api.format'].should eql nil
|
49
49
|
status.should == 200
|
@@ -54,13 +54,13 @@ describe Grape::Middleware::Versioner::Header do
|
|
54
54
|
@options[:versions] = ['v1']
|
55
55
|
end
|
56
56
|
|
57
|
-
it '
|
57
|
+
it 'is set' do
|
58
58
|
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1+json')
|
59
59
|
env['api.format'].should eql 'json'
|
60
60
|
status.should == 200
|
61
61
|
end
|
62
62
|
|
63
|
-
it '
|
63
|
+
it 'is nil if not provided' do
|
64
64
|
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1')
|
65
65
|
env['api.format'].should eql nil
|
66
66
|
status.should == 200
|
@@ -69,19 +69,19 @@ describe Grape::Middleware::Versioner::Header do
|
|
69
69
|
end
|
70
70
|
|
71
71
|
context 'api.vendor' do
|
72
|
-
it '
|
72
|
+
it 'is set' do
|
73
73
|
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor')
|
74
74
|
env['api.vendor'].should eql 'vendor'
|
75
75
|
status.should == 200
|
76
76
|
end
|
77
77
|
|
78
|
-
it '
|
78
|
+
it 'is set if format provided' do
|
79
79
|
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor+json')
|
80
80
|
env['api.vendor'].should eql 'vendor'
|
81
81
|
status.should == 200
|
82
82
|
end
|
83
83
|
|
84
|
-
it '
|
84
|
+
it 'fails with 406 Not Acceptable if vendor is invalid' do
|
85
85
|
expect {
|
86
86
|
env = subject.call('HTTP_ACCEPT' => 'application/vnd.othervendor+json').last
|
87
87
|
}.to throw_symbol(
|
@@ -97,19 +97,19 @@ describe Grape::Middleware::Versioner::Header do
|
|
97
97
|
@options[:versions] = ['v1']
|
98
98
|
end
|
99
99
|
|
100
|
-
it '
|
100
|
+
it 'is set' do
|
101
101
|
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1')
|
102
102
|
env['api.vendor'].should eql 'vendor'
|
103
103
|
status.should == 200
|
104
104
|
end
|
105
105
|
|
106
|
-
it '
|
106
|
+
it 'is set if format provided' do
|
107
107
|
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1+json')
|
108
108
|
env['api.vendor'].should eql 'vendor'
|
109
109
|
status.should == 200
|
110
110
|
end
|
111
111
|
|
112
|
-
it '
|
112
|
+
it 'fails with 406 Not Acceptable if vendor is invalid' do
|
113
113
|
expect {
|
114
114
|
env = subject.call('HTTP_ACCEPT' => 'application/vnd.othervendor-v1+json').last
|
115
115
|
}.to throw_symbol(
|
@@ -127,19 +127,19 @@ describe Grape::Middleware::Versioner::Header do
|
|
127
127
|
@options[:versions] = ['v1']
|
128
128
|
end
|
129
129
|
|
130
|
-
it '
|
130
|
+
it 'is set' do
|
131
131
|
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1')
|
132
132
|
env['api.version'].should eql 'v1'
|
133
133
|
status.should == 200
|
134
134
|
end
|
135
135
|
|
136
|
-
it '
|
136
|
+
it 'is set if format provided' do
|
137
137
|
status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1+json')
|
138
138
|
env['api.version'].should eql 'v1'
|
139
139
|
status.should == 200
|
140
140
|
end
|
141
141
|
|
142
|
-
it '
|
142
|
+
it 'fails with 406 Not Acceptable if version is invalid' do
|
143
143
|
expect {
|
144
144
|
env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v2+json').last
|
145
145
|
}.to throw_symbol(
|
@@ -151,12 +151,12 @@ describe Grape::Middleware::Versioner::Header do
|
|
151
151
|
end
|
152
152
|
end
|
153
153
|
|
154
|
-
it '
|
154
|
+
it 'succeeds if :strict is not set' do
|
155
155
|
subject.call('HTTP_ACCEPT' => '').first.should == 200
|
156
156
|
subject.call({}).first.should == 200
|
157
157
|
end
|
158
158
|
|
159
|
-
it '
|
159
|
+
it 'succeeds if :strict is set to false' do
|
160
160
|
@options[:version_options][:strict] = false
|
161
161
|
subject.call('HTTP_ACCEPT' => '').first.should == 200
|
162
162
|
subject.call({}).first.should == 200
|
@@ -168,7 +168,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
168
168
|
@options[:version_options][:strict] = true
|
169
169
|
end
|
170
170
|
|
171
|
-
it '
|
171
|
+
it 'fails with 406 Not Acceptable if header is not set' do
|
172
172
|
expect {
|
173
173
|
env = subject.call({}).last
|
174
174
|
}.to throw_symbol(
|
@@ -179,7 +179,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
179
179
|
)
|
180
180
|
end
|
181
181
|
|
182
|
-
it '
|
182
|
+
it 'fails with 406 Not Acceptable if header is empty' do
|
183
183
|
expect {
|
184
184
|
env = subject.call('HTTP_ACCEPT' => '').last
|
185
185
|
}.to throw_symbol(
|
@@ -190,7 +190,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
190
190
|
)
|
191
191
|
end
|
192
192
|
|
193
|
-
it '
|
193
|
+
it 'fails with 406 Not Acceptable if type is a range' do
|
194
194
|
expect {
|
195
195
|
env = subject.call('HTTP_ACCEPT' => '*/*').last
|
196
196
|
}.to throw_symbol(
|
@@ -201,7 +201,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
201
201
|
)
|
202
202
|
end
|
203
203
|
|
204
|
-
it '
|
204
|
+
it 'fails with 406 Not Acceptable if subtype is a range' do
|
205
205
|
expect {
|
206
206
|
env = subject.call('HTTP_ACCEPT' => 'application/*').last
|
207
207
|
}.to throw_symbol(
|
@@ -212,7 +212,7 @@ describe Grape::Middleware::Versioner::Header do
|
|
212
212
|
)
|
213
213
|
end
|
214
214
|
|
215
|
-
it '
|
215
|
+
it 'succeeds if proper header is set' do
|
216
216
|
subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1+json').first.should == 200
|
217
217
|
end
|
218
218
|
end
|