drillbit 2.11.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/drillbit.rb +1 -0
- data/lib/drillbit/accept_header.rb +1 -0
- data/lib/drillbit/authorizable_resource.rb +61 -60
- data/lib/drillbit/authorizers/parameters.rb +1 -0
- data/lib/drillbit/authorizers/parameters/filtering.rb +7 -6
- data/lib/drillbit/authorizers/parameters/inclusions.rb +6 -9
- data/lib/drillbit/authorizers/parameters/resource.rb +20 -19
- data/lib/drillbit/authorizers/query.rb +1 -0
- data/lib/drillbit/authorizers/scope.rb +5 -4
- data/lib/drillbit/compatibility/controllers.rb +1 -0
- data/lib/drillbit/configuration.rb +14 -16
- data/lib/drillbit/errors/invalid_api_request.rb +1 -0
- data/lib/drillbit/errors/invalid_request_body.rb +1 -0
- data/lib/drillbit/errors/invalid_subdomain.rb +1 -0
- data/lib/drillbit/errors/invalid_token.rb +1 -0
- data/lib/drillbit/errors/unpermitted_inclusions.rb +1 -0
- data/lib/drillbit/matchers/accept_header.rb +1 -0
- data/lib/drillbit/matchers/generic.rb +4 -3
- data/lib/drillbit/matchers/subdomain.rb +5 -6
- data/lib/drillbit/matchers/version.rb +3 -2
- data/lib/drillbit/middleware/api_request_validator.rb +4 -3
- data/lib/drillbit/middleware/parameter_parser.rb +1 -0
- data/lib/drillbit/middleware/token_processor.rb +1 -0
- data/lib/drillbit/parameters/filter.rb +12 -11
- data/lib/drillbit/parameters/index.rb +3 -2
- data/lib/drillbit/parameters/page.rb +1 -0
- data/lib/drillbit/parameters/sort.rb +1 -0
- data/lib/drillbit/requests/base.rb +1 -1
- data/lib/drillbit/requests/rack.rb +3 -0
- data/lib/drillbit/requests/rails.rb +1 -0
- data/lib/drillbit/resource.rb +1 -0
- data/lib/drillbit/resource/model.rb +5 -4
- data/lib/drillbit/resource/naming.rb +11 -10
- data/lib/drillbit/resource/processors/filtering.rb +1 -0
- data/lib/drillbit/resource/processors/indexing.rb +1 -0
- data/lib/drillbit/resource/processors/paging.rb +4 -3
- data/lib/drillbit/resource/processors/sorting.rb +1 -0
- data/lib/drillbit/responses/invalid_api_request.rb +3 -0
- data/lib/drillbit/responses/invalid_request_body.rb +3 -0
- data/lib/drillbit/responses/invalid_subdomain.rb +3 -0
- data/lib/drillbit/responses/invalid_token.rb +3 -0
- data/lib/drillbit/serializers/json_api.rb +12 -11
- data/lib/drillbit/tokens/base64.rb +1 -0
- data/lib/drillbit/tokens/base64s/invalid.rb +1 -0
- data/lib/drillbit/tokens/base64s/null.rb +1 -0
- data/lib/drillbit/tokens/invalid.rb +1 -0
- data/lib/drillbit/tokens/json_web_token.rb +6 -5
- data/lib/drillbit/tokens/json_web_tokens/invalid.rb +1 -0
- data/lib/drillbit/tokens/json_web_tokens/null.rb +1 -0
- data/lib/drillbit/tokens/json_web_tokens/password_reset.rb +1 -0
- data/lib/drillbit/tokens/null.rb +1 -0
- data/lib/drillbit/utilities/string.rb +1 -0
- data/lib/drillbit/version.rb +2 -1
- metadata +28 -94
- metadata.gz.sig +0 -0
- data/Rakefile +0 -2
- data/spec/drillbit/accept_header_spec.rb +0 -119
- data/spec/drillbit/authorizers/parameters/filtering_spec.rb +0 -101
- data/spec/drillbit/authorizers/parameters/resource_spec.rb +0 -12
- data/spec/drillbit/authorizers/parameters_spec.rb +0 -19
- data/spec/drillbit/authorizers/query_spec.rb +0 -24
- data/spec/drillbit/authorizers/scope_spec.rb +0 -21
- data/spec/drillbit/errors/invalid_api_request_spec.rb +0 -31
- data/spec/drillbit/errors/invalid_request_body_spec.rb +0 -25
- data/spec/drillbit/errors/invalid_subdomain_spec.rb +0 -30
- data/spec/drillbit/errors/invalid_token_spec.rb +0 -24
- data/spec/drillbit/invalid_subdomain_spec.rb +0 -45
- data/spec/drillbit/invalid_token_spec.rb +0 -44
- data/spec/drillbit/matchers/accept_header_spec.rb +0 -114
- data/spec/drillbit/matchers/subdomain_spec.rb +0 -78
- data/spec/drillbit/matchers/version_spec.rb +0 -86
- data/spec/drillbit/middleware/api_request_validator_spec.rb +0 -185
- data/spec/drillbit/middleware/parameter_parser_spec.rb +0 -200
- data/spec/drillbit/middleware/token_processor_spec.rb +0 -27
- data/spec/drillbit/requests/base_spec.rb +0 -37
- data/spec/drillbit/requests/rack_spec.rb +0 -252
- data/spec/drillbit/requests/rails_spec.rb +0 -264
- data/spec/drillbit/resource/model_spec.rb +0 -64
- data/spec/drillbit/resource/processors/filtering_spec.rb +0 -106
- data/spec/drillbit/resource/processors/indexing_spec.rb +0 -45
- data/spec/drillbit/resource/processors/paging_spec.rb +0 -74
- data/spec/drillbit/resource/processors/sorting_spec.rb +0 -66
- data/spec/drillbit/tokens/base64_spec.rb +0 -44
- data/spec/drillbit/tokens/json_web_token_spec.rb +0 -231
- data/spec/drillbit/tokens/json_web_tokens/password_reset_spec.rb +0 -43
- data/spec/fixtures/test_rsa_key +0 -27
- data/spec/fixtures/test_rsa_key.pub +0 -9
- data/spec/spec_helper.rb +0 -4
- data/spec/support/private_keys.rb +0 -42
@@ -1,78 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'rspeckled/spec_helpers/rspeckled'
|
3
|
-
require 'drillbit/requests/base'
|
4
|
-
require 'drillbit/matchers/subdomain'
|
5
|
-
require 'drillbit/configuration'
|
6
|
-
|
7
|
-
module Drillbit
|
8
|
-
module Matchers
|
9
|
-
describe Subdomain do
|
10
|
-
before(:each) do
|
11
|
-
Drillbit.configuration.allowed_subdomains = %w{api}
|
12
|
-
Drillbit.configuration.allowed_api_subdomains = %w{api}
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'matches if the subdomain is API' do
|
16
|
-
env = { 'HTTP_HOST' => 'api.example.com' }
|
17
|
-
request = Requests::Base.resolve(env)
|
18
|
-
matcher = Subdomain.new
|
19
|
-
|
20
|
-
expect(matcher.matches?(request)).to be_a TrueClass
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'matches if the first subdomain is API' do
|
24
|
-
env = { 'HTTP_HOST' => 'api.westeros.example.com' }
|
25
|
-
request = Requests::Base.resolve(env)
|
26
|
-
matcher = Subdomain.new
|
27
|
-
|
28
|
-
expect(matcher.matches?(request)).to be_a TrueClass
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'does not match if the first subdomain is not API' do
|
32
|
-
env = { 'HTTP_HOST' => 'westeros.example.com' }
|
33
|
-
request = Requests::Base.resolve(env)
|
34
|
-
matcher = Subdomain.new
|
35
|
-
|
36
|
-
expect(matcher.matches?(request)).to be_a FalseClass
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'allows the matched subdomain to be specified' do
|
40
|
-
env = { 'HTTP_HOST' => 'westeros.example.com' }
|
41
|
-
request = Requests::Base.resolve(env)
|
42
|
-
matcher = Subdomain.new(allowed_subdomains: 'westeros')
|
43
|
-
|
44
|
-
expect(matcher.matches?(request)).to be_a TrueClass
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'allows more than one subdomain to be matched' do
|
48
|
-
env = { 'HTTP_HOST' => 'westeros.example.com' }
|
49
|
-
request = Requests::Base.resolve(env)
|
50
|
-
matcher = Subdomain.new(allowed_subdomains: %w{api westeros})
|
51
|
-
|
52
|
-
expect(matcher.matches?(request)).to be_a TrueClass
|
53
|
-
|
54
|
-
env = { 'HTTP_HOST' => 'api.example.com' }
|
55
|
-
request = Requests::Base.resolve(env)
|
56
|
-
matcher = Subdomain.new(allowed_subdomains: %w{api westeros})
|
57
|
-
|
58
|
-
expect(matcher.matches?(request)).to be_a TrueClass
|
59
|
-
end
|
60
|
-
|
61
|
-
it 'can match only the api subdomain' do
|
62
|
-
env = { 'HTTP_HOST' => 'westeros.example.com' }
|
63
|
-
request = Requests::Base.resolve(env)
|
64
|
-
matcher = Subdomain.new(allowed_api_subdomains: %w{westeros})
|
65
|
-
|
66
|
-
expect(matcher.matches_api_subdomain?(request)).to be_a TrueClass
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'matches "api" as an api subdomain by default' do
|
70
|
-
env = { 'HTTP_HOST' => 'api.example.com' }
|
71
|
-
request = Requests::Base.resolve(env)
|
72
|
-
matcher = Subdomain.new
|
73
|
-
|
74
|
-
expect(matcher.matches_api_subdomain?(request)).to be_a TrueClass
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'rspeckled/spec_helpers/rspeckled'
|
3
|
-
require 'drillbit/requests/base'
|
4
|
-
require 'drillbit/matchers/version'
|
5
|
-
|
6
|
-
module Drillbit
|
7
|
-
module Matchers
|
8
|
-
describe Version do
|
9
|
-
context 'when the version is passed in the accept header' do
|
10
|
-
it 'does not match if the subdomain is API but the requested version does not ' \
|
11
|
-
'equal the version constraint' do
|
12
|
-
|
13
|
-
env = {
|
14
|
-
'HTTP_X_APPLICATION_NAME' => 'westeros',
|
15
|
-
'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep;version=10.0',
|
16
|
-
}
|
17
|
-
request = Requests::Base.resolve(env)
|
18
|
-
|
19
|
-
matcher = Version.new(version_constraint: '10.1')
|
20
|
-
|
21
|
-
expect(matcher.matches?(request)).to be_a FalseClass
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'does match if the subdomain is API and the requested version equals the ' \
|
25
|
-
'version constraint' do
|
26
|
-
|
27
|
-
env = {
|
28
|
-
'HTTP_X_APPLICATION_NAME' => 'westeros',
|
29
|
-
'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep;version=10.0',
|
30
|
-
}
|
31
|
-
request = Requests::Base.resolve(env)
|
32
|
-
|
33
|
-
matcher = Version.new(version_constraint: '10.0')
|
34
|
-
|
35
|
-
expect(matcher.matches?(request)).to be_a TrueClass
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
context 'when the version is not passed in the accept header' do
|
40
|
-
it 'does not match if the subdomain is API but the requested version does not ' \
|
41
|
-
'equal the version constraint' do
|
42
|
-
|
43
|
-
env = {
|
44
|
-
'HTTP_X_APPLICATION_NAME' => 'westeros',
|
45
|
-
'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep',
|
46
|
-
}
|
47
|
-
request = Requests::Base.resolve(env)
|
48
|
-
|
49
|
-
matcher = Version.new(version_constraint: '10.1',
|
50
|
-
default_version: '10.0')
|
51
|
-
|
52
|
-
expect(matcher.matches?(request)).to be_a FalseClass
|
53
|
-
end
|
54
|
-
|
55
|
-
it 'does match if the subdomain is API and the requested version equals the ' \
|
56
|
-
'version constraint' do
|
57
|
-
|
58
|
-
env = {
|
59
|
-
'HTTP_X_APPLICATION_NAME' => 'westeros',
|
60
|
-
'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep',
|
61
|
-
}
|
62
|
-
request = Requests::Base.resolve(env)
|
63
|
-
|
64
|
-
matcher = Version.new(version_constraint: '10.0',
|
65
|
-
default_version: '10.0')
|
66
|
-
|
67
|
-
expect(matcher.matches?(request)).to be_a TrueClass
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
it 'matches the default version in the configuration if none is passed in' do
|
72
|
-
Drillbit.configuration.default_api_version = '100.0'
|
73
|
-
|
74
|
-
env = {
|
75
|
-
'HTTP_X_APPLICATION_NAME' => 'westeros',
|
76
|
-
'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep',
|
77
|
-
}
|
78
|
-
request = Requests::Base.resolve(env)
|
79
|
-
|
80
|
-
matcher = Version.new(version_constraint: '100.0')
|
81
|
-
|
82
|
-
expect(matcher.matches?(request)).to be_a TrueClass
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
@@ -1,185 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'rspeckled/spec_helpers/rspeckled'
|
3
|
-
require 'drillbit/middleware/api_request_validator'
|
4
|
-
|
5
|
-
# rubocop:disable Metrics/LineLength
|
6
|
-
module Drillbit
|
7
|
-
module Middleware
|
8
|
-
describe ApiRequestValidator, singletons: Erratum::Configuration do
|
9
|
-
let(:app) { ->(_env) { [200, {}, 'response'] } }
|
10
|
-
|
11
|
-
before(:each) do
|
12
|
-
Erratum.configuration.url_mappings = {
|
13
|
-
'external_documentation_urls' => {
|
14
|
-
'errors.responses.invalid_subdomain' => 'http://example.com/foo',
|
15
|
-
},
|
16
|
-
'developer_documentation_urls' => {
|
17
|
-
'errors.responses.invalid_subdomain' => 'http://example.com/foo',
|
18
|
-
},
|
19
|
-
}
|
20
|
-
|
21
|
-
Drillbit.configure do |config|
|
22
|
-
config.allowed_subdomains = %w{api westeros}
|
23
|
-
config.allowed_api_subdomains = %w{api}
|
24
|
-
config.application_name = 'westeros'
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'allows requests for allowed subdomains without accept headers' do
|
29
|
-
api_request_middleware = ApiRequestValidator.new(app)
|
30
|
-
|
31
|
-
request = {
|
32
|
-
'HTTP_HOST' => 'westeros.example.com',
|
33
|
-
'HTTP_ACCEPT' => '',
|
34
|
-
'QUERY_STRING' => '',
|
35
|
-
}
|
36
|
-
|
37
|
-
status, headers, response = api_request_middleware.call(request)
|
38
|
-
|
39
|
-
expect(status).to eql 200
|
40
|
-
expect(headers).to eql({})
|
41
|
-
expect(response).to eql 'response'
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'does not allow requests if they are not for an allowed subdomain' do
|
45
|
-
api_request_middleware = ApiRequestValidator.new(app)
|
46
|
-
|
47
|
-
request = {
|
48
|
-
'HTTP_HOST' => 'notvalid.example.com',
|
49
|
-
'HTTP_ACCEPT' => '',
|
50
|
-
'QUERY_STRING' => 'first=my_param&accept=application/vnd.silent+redkeep;version=1.0.0',
|
51
|
-
}
|
52
|
-
|
53
|
-
status, headers, response = api_request_middleware.call(request)
|
54
|
-
|
55
|
-
expect(status).to eql 404
|
56
|
-
expect(headers).to eql({})
|
57
|
-
expect(JSON.load(response[0])).to include(
|
58
|
-
'errors' => [
|
59
|
-
{
|
60
|
-
'id' => match(/[a-z0-9\-]+/),
|
61
|
-
'links' => {
|
62
|
-
'about' => nil,
|
63
|
-
'documentation' => nil,
|
64
|
-
},
|
65
|
-
'status' => 404,
|
66
|
-
'code' => 'errors.invalid_subdomain',
|
67
|
-
'title' => 'Invalid Subdomain',
|
68
|
-
'detail' => 'The subdomain you attempted to access is not valid.' \
|
69
|
-
' Please try again.',
|
70
|
-
'source' => {
|
71
|
-
'http_host' => 'notvalid.example.com',
|
72
|
-
},
|
73
|
-
},
|
74
|
-
],
|
75
|
-
)
|
76
|
-
end
|
77
|
-
|
78
|
-
it 'does not allow requests if they are for an allowed subdomain but does ' \
|
79
|
-
'not have a valid accept header' do
|
80
|
-
|
81
|
-
api_request_middleware = ApiRequestValidator.new(app)
|
82
|
-
|
83
|
-
request = {
|
84
|
-
'HTTP_HOST' => 'api.example.com',
|
85
|
-
'HTTP_ACCEPT' => '',
|
86
|
-
'QUERY_STRING' => 'first=my_param&accept=application/vnd.silent+redkeep;version=1.0.0',
|
87
|
-
}
|
88
|
-
|
89
|
-
status, headers, response = api_request_middleware.call(request)
|
90
|
-
|
91
|
-
expect(status).to eql 400
|
92
|
-
expect(headers).to eql({})
|
93
|
-
expect(JSON.load(response[0])).to include(
|
94
|
-
'errors' => [
|
95
|
-
{
|
96
|
-
'id' => match(/[a-z0-9\-]+/),
|
97
|
-
'links' => {
|
98
|
-
'about' => nil,
|
99
|
-
'documentation' => nil,
|
100
|
-
},
|
101
|
-
'status' => 400,
|
102
|
-
'code' => 'errors.invalid_api_request',
|
103
|
-
'title' => 'Invalid API Request',
|
104
|
-
'detail' => 'The accept header that you passed in the request cannot be ' \
|
105
|
-
'parsed, please refer to the documentation to verify.',
|
106
|
-
'source' => {
|
107
|
-
'accept_header' => '',
|
108
|
-
},
|
109
|
-
},
|
110
|
-
],
|
111
|
-
)
|
112
|
-
end
|
113
|
-
|
114
|
-
it 'does allow requests if both the subdomain and the accept header are valid' do
|
115
|
-
api_request_middleware = ApiRequestValidator.new(app)
|
116
|
-
|
117
|
-
request = {
|
118
|
-
'HTTP_HOST' => 'api.example.com',
|
119
|
-
'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep;version=1.0.0',
|
120
|
-
'QUERY_STRING' => 'first=my_param&accept=application/vnd.westeros+redkeep;version=1.0.0',
|
121
|
-
}
|
122
|
-
|
123
|
-
status, headers, response = api_request_middleware.call(request)
|
124
|
-
|
125
|
-
expect(status).to eql 200
|
126
|
-
expect(headers).to eql({})
|
127
|
-
expect(response).to eql 'response'
|
128
|
-
end
|
129
|
-
|
130
|
-
it 'does allow requests if the subdomain, the accept header and the token are valid' do
|
131
|
-
Drillbit.configuration.token_private_key = test_private_key
|
132
|
-
api_request_middleware = ApiRequestValidator.new(app)
|
133
|
-
|
134
|
-
request = {
|
135
|
-
'HTTP_HOST' => 'api.example.com',
|
136
|
-
'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep;version=1.0.0',
|
137
|
-
'HTTP_AUTHORIZATION' => "Token #{valid_jwe_token}",
|
138
|
-
'QUERY_STRING' => 'accept=application/vnd.westeros+redkeep;version=1.0.0',
|
139
|
-
}
|
140
|
-
|
141
|
-
status, headers, response = api_request_middleware.call(request)
|
142
|
-
|
143
|
-
expect(status).to eql 200
|
144
|
-
expect(headers).to eql({})
|
145
|
-
expect(response).to eql 'response'
|
146
|
-
end
|
147
|
-
|
148
|
-
it 'properly converts the content type for Rails when it is the only one' do
|
149
|
-
api_request_middleware = ApiRequestValidator.new(app)
|
150
|
-
|
151
|
-
request = {
|
152
|
-
'CONTENT_TYPE' => 'application/vnd.api+json',
|
153
|
-
'HTTP_HOST' => 'westeros.example.com',
|
154
|
-
'HTTP_ACCEPT' => '',
|
155
|
-
'QUERY_STRING' => '',
|
156
|
-
}
|
157
|
-
|
158
|
-
allow(app).to receive(:call)
|
159
|
-
|
160
|
-
_response = api_request_middleware.call(request)
|
161
|
-
|
162
|
-
expect(app).to have_received(:call).
|
163
|
-
with(a_hash_including('CONTENT_TYPE' => 'application/json'))
|
164
|
-
end
|
165
|
-
|
166
|
-
it 'properly converts the content type for Rails when it is not the only one' do
|
167
|
-
api_request_middleware = ApiRequestValidator.new(app)
|
168
|
-
|
169
|
-
request = {
|
170
|
-
'CONTENT_TYPE' => 'application/vnd.api+json;other',
|
171
|
-
'HTTP_HOST' => 'westeros.example.com',
|
172
|
-
'HTTP_ACCEPT' => '',
|
173
|
-
'QUERY_STRING' => '',
|
174
|
-
}
|
175
|
-
|
176
|
-
allow(app).to receive(:call)
|
177
|
-
|
178
|
-
_response = api_request_middleware.call(request)
|
179
|
-
|
180
|
-
expect(app).to have_received(:call).
|
181
|
-
with(a_hash_including('CONTENT_TYPE' => 'application/json;other'))
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
@@ -1,200 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'spec_helper'
|
3
|
-
require 'drillbit/middleware/parameter_parser'
|
4
|
-
|
5
|
-
module Drillbit
|
6
|
-
module Middleware
|
7
|
-
describe ParameterParser do
|
8
|
-
let(:app) { ->(_env) { [200, {}, 'response'] } }
|
9
|
-
|
10
|
-
it 'converts JSON API compliant dasherized query params to underscored' do
|
11
|
-
app = ->(env) { [200, env, 'response'] }
|
12
|
-
middleware = ParameterParser.new(app)
|
13
|
-
|
14
|
-
request = {
|
15
|
-
'QUERY_STRING' => 'hello-there=bob-jones&' \
|
16
|
-
'nice-to-meet=you-bob&' \
|
17
|
-
'hows-the-weather=today-bob',
|
18
|
-
}
|
19
|
-
|
20
|
-
_status, headers, _response = middleware.call(request)
|
21
|
-
|
22
|
-
expect(headers['QUERY_STRING']).to eql 'hello_there=bob-jones&' \
|
23
|
-
'nice_to_meet=you-bob&' \
|
24
|
-
'hows_the_weather=today-bob'
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'does not touch query params with no dashes' do
|
28
|
-
app = ->(env) { [200, env, 'response'] }
|
29
|
-
middleware = ParameterParser.new(app)
|
30
|
-
|
31
|
-
request = {
|
32
|
-
'QUERY_STRING' => 'hello_there=bob-jones',
|
33
|
-
}
|
34
|
-
|
35
|
-
_status, headers, _response = middleware.call(request)
|
36
|
-
|
37
|
-
expect(headers['QUERY_STRING']).to eql 'hello_there=bob-jones'
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'can handle weirdly formatted query string parameters' do
|
41
|
-
app = ->(env) { [200, env, 'response'] }
|
42
|
-
middleware = ParameterParser.new(app)
|
43
|
-
|
44
|
-
request = {
|
45
|
-
'QUERY_STRING' => 'hello-there=bob-jones&' \
|
46
|
-
'nice-to-meet=you-bob&=',
|
47
|
-
}
|
48
|
-
|
49
|
-
_status, headers, _response = middleware.call(request)
|
50
|
-
|
51
|
-
expect(headers['QUERY_STRING']).to eql 'hello_there=bob-jones&' \
|
52
|
-
'nice_to_meet=you-bob&='
|
53
|
-
end
|
54
|
-
|
55
|
-
it 'can handle query string parameters with no values' do
|
56
|
-
app = ->(env) { [200, env, 'response'] }
|
57
|
-
middleware = ParameterParser.new(app)
|
58
|
-
|
59
|
-
request = {
|
60
|
-
'QUERY_STRING' => 'hello-there&nice-to-meet=you-bob&=',
|
61
|
-
}
|
62
|
-
|
63
|
-
_status, headers, _response = middleware.call(request)
|
64
|
-
|
65
|
-
expect(headers['QUERY_STRING']).to eql 'hello_there&nice_to_meet=you-bob&='
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'can handle query string parameters with parameter name' do
|
69
|
-
app = ->(env) { [200, env, 'response'] }
|
70
|
-
middleware = ParameterParser.new(app)
|
71
|
-
|
72
|
-
request = {
|
73
|
-
'QUERY_STRING' => 'hello-there=bob-jones&=you-bob&nice-to-meet=you-bob&=',
|
74
|
-
}
|
75
|
-
|
76
|
-
_status, headers, _response = middleware.call(request)
|
77
|
-
|
78
|
-
expect(headers['QUERY_STRING']).to eql 'hello_there=bob-jones&' \
|
79
|
-
'=you-bob&' \
|
80
|
-
'nice_to_meet=you-bob&='
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'converts JSON API compliant dasherized request params to underscored' do
|
84
|
-
app = ->(env) { [200, env, 'response'] }
|
85
|
-
middleware = ParameterParser.new(app)
|
86
|
-
|
87
|
-
request = {
|
88
|
-
'CONTENT_LENGTH' => '1',
|
89
|
-
'CONTENT_TYPE' => 'application/json',
|
90
|
-
'RACK_INPUT' => <<-HEREDOC
|
91
|
-
{
|
92
|
-
"single": "word",
|
93
|
-
"double-word": "double double",
|
94
|
-
"triple": {
|
95
|
-
"trippple-tripple": "mcdipple",
|
96
|
-
"quad": {
|
97
|
-
"another-level": "whoa inception"
|
98
|
-
}
|
99
|
-
},
|
100
|
-
"quint": [
|
101
|
-
{
|
102
|
-
"quint-it-quit": "mc-dipple"
|
103
|
-
},
|
104
|
-
{
|
105
|
-
"quint-it-quit": "big-maccle"
|
106
|
-
}
|
107
|
-
]
|
108
|
-
}
|
109
|
-
HEREDOC
|
110
|
-
}
|
111
|
-
|
112
|
-
_status, headers, _response = middleware.call(request)
|
113
|
-
|
114
|
-
expect(JSON.load(headers['RACK_INPUT'])).to eql(
|
115
|
-
'single' => 'word',
|
116
|
-
'double_word' => 'double double',
|
117
|
-
'triple' => {
|
118
|
-
'trippple_tripple' => 'mcdipple',
|
119
|
-
'quad' => {
|
120
|
-
'another_level' => 'whoa inception',
|
121
|
-
},
|
122
|
-
},
|
123
|
-
'quint' => [
|
124
|
-
{
|
125
|
-
'quint_it_quit' => 'mc-dipple',
|
126
|
-
},
|
127
|
-
{
|
128
|
-
'quint_it_quit' => 'big-maccle',
|
129
|
-
},
|
130
|
-
],
|
131
|
-
)
|
132
|
-
end
|
133
|
-
|
134
|
-
it 'does not convert to JSON if the content type is not JSON' do
|
135
|
-
app = ->(env) { [200, env, 'response'] }
|
136
|
-
middleware = ParameterParser.new(app)
|
137
|
-
|
138
|
-
request = {
|
139
|
-
'CONTENT_LENGTH' => '1',
|
140
|
-
'CONTENT_TYPE' => 'not_j_s_o_n',
|
141
|
-
'RACK_INPUT' => 'This is not JSON',
|
142
|
-
}
|
143
|
-
|
144
|
-
_status, headers, _response = middleware.call(request)
|
145
|
-
|
146
|
-
expect(headers['RACK_INPUT']).to eql 'This is not JSON'
|
147
|
-
end
|
148
|
-
|
149
|
-
it 'does not convert to JSON if there is no content' do
|
150
|
-
app = ->(env) { [200, env, 'response'] }
|
151
|
-
middleware = ParameterParser.new(app)
|
152
|
-
|
153
|
-
request = {
|
154
|
-
'CONTENT_LENGTH' => '0',
|
155
|
-
'CONTENT_TYPE' => 'application/json',
|
156
|
-
'RACK_INPUT' => 'empty',
|
157
|
-
}
|
158
|
-
|
159
|
-
_status, headers, _response = middleware.call(request)
|
160
|
-
|
161
|
-
expect(headers['RACK_INPUT']).to eql 'empty'
|
162
|
-
end
|
163
|
-
|
164
|
-
it 'can handle incorrectly formatted JSON' do
|
165
|
-
app = ->(env) { [200, env, 'response'] }
|
166
|
-
middleware = ParameterParser.new(app)
|
167
|
-
|
168
|
-
request = {
|
169
|
-
'CONTENT_LENGTH' => '1',
|
170
|
-
'CONTENT_TYPE' => 'application/json',
|
171
|
-
'RACK_INPUT' => 'something blah',
|
172
|
-
}
|
173
|
-
|
174
|
-
status, headers, response = middleware.call(request)
|
175
|
-
|
176
|
-
expect(status).to eql 400
|
177
|
-
expect(headers).to eql({})
|
178
|
-
expect(JSON.load(response[0])).to include(
|
179
|
-
'errors' => [
|
180
|
-
{
|
181
|
-
'id' => match(/[a-z0-9\-]+/),
|
182
|
-
'links' => {
|
183
|
-
'about' => nil,
|
184
|
-
'documentation' => nil,
|
185
|
-
},
|
186
|
-
'status' => 400,
|
187
|
-
'code' => 'errors.invalid_request_body',
|
188
|
-
'title' => 'Invalid Request Body',
|
189
|
-
'detail' => 'The information you attempted to send in the ' \
|
190
|
-
'request cannot be parsed as a valid JSON document.',
|
191
|
-
'source' => {
|
192
|
-
'request_body' => 'something blah',
|
193
|
-
},
|
194
|
-
},
|
195
|
-
],
|
196
|
-
)
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|