committee 3.2.1 → 3.3.0
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.
- checksums.yaml +4 -4
- data/lib/committee/middleware/base.rb +3 -1
- data/lib/committee/middleware/request_validation.rb +17 -19
- data/lib/committee/middleware/response_validation.rb +0 -1
- data/test/middleware/request_validation_open_api_3_test.rb +23 -0
- data/test/middleware/request_validation_test.rb +26 -0
- data/test/middleware/response_validation_open_api_3_test.rb +49 -21
- data/test/middleware/response_validation_test.rb +16 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0c35304cf9026ae20062ea312cdca6b43af486c4c2e5e7c952b35bbad811ce4e
|
|
4
|
+
data.tar.gz: d9a96cd2c6c15b9de26fb95ef0b4d59216c999f8589329d6ee6b21b41e2511d9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 42ffc889dcc301c9de500417390454f4723bf049f0336b9de92b94fcaa2d67f53a7f5c4c9ad5a3a56bd2e9fff70d06ebe7c7279729c616b45ab33625c2a33572
|
|
7
|
+
data.tar.gz: d3c7ca273497b2eb4444fcdb6eb43f49fed866335d1a627f806586f6755557b8a956b43eb5c9448b7cf19176b9e2a4705c78bf6045dde2e98b19fd55211e0070
|
|
@@ -8,17 +8,19 @@ module Committee
|
|
|
8
8
|
|
|
9
9
|
@error_class = options.fetch(:error_class, Committee::ValidationError)
|
|
10
10
|
@error_handler = options[:error_handler]
|
|
11
|
+
@ignore_error = options.fetch(:ignore_error, false)
|
|
11
12
|
|
|
12
13
|
@raise = options[:raise]
|
|
13
14
|
@schema = self.class.get_schema(options)
|
|
14
15
|
|
|
15
16
|
@router = @schema.build_router(options)
|
|
17
|
+
@accept_request_filter = options[:accept_request_filter] || -> (_) { true }
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
def call(env)
|
|
19
21
|
request = Rack::Request.new(env)
|
|
20
22
|
|
|
21
|
-
if @router.includes_request?(request)
|
|
23
|
+
if @router.includes_request?(request) && @accept_request_filter.call(request)
|
|
22
24
|
handle(request)
|
|
23
25
|
else
|
|
24
26
|
@app.call(request.env)
|
|
@@ -13,27 +13,25 @@ module Committee
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def handle(request)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
begin
|
|
17
|
+
schema_validator = build_schema_validator(request)
|
|
18
|
+
schema_validator.request_validate(request)
|
|
19
|
+
|
|
20
|
+
raise Committee::NotFound, "That request method and path combination isn't defined." if !schema_validator.link_exist? && @strict
|
|
21
|
+
rescue Committee::BadRequest, Committee::InvalidRequest
|
|
22
|
+
handle_exception($!, request.env)
|
|
23
|
+
raise if @raise
|
|
24
|
+
return @error_class.new(400, :bad_request, $!.message).render unless @ignore_error
|
|
25
|
+
rescue Committee::NotFound => e
|
|
26
|
+
raise if @raise
|
|
27
|
+
return @error_class.new(404, :not_found, e.message).render unless @ignore_error
|
|
28
|
+
rescue JSON::ParserError
|
|
29
|
+
handle_exception($!, request.env)
|
|
30
|
+
raise Committee::InvalidRequest if @raise
|
|
31
|
+
return @error_class.new(400, :bad_request, "Request body wasn't valid JSON.").render unless @ignore_error
|
|
32
|
+
end
|
|
20
33
|
|
|
21
34
|
@app.call(request.env)
|
|
22
|
-
rescue Committee::BadRequest, Committee::InvalidRequest
|
|
23
|
-
handle_exception($!, request.env)
|
|
24
|
-
raise if @raise
|
|
25
|
-
@error_class.new(400, :bad_request, $!.message).render
|
|
26
|
-
rescue Committee::NotFound => e
|
|
27
|
-
raise if @raise
|
|
28
|
-
@error_class.new(
|
|
29
|
-
404,
|
|
30
|
-
:not_found,
|
|
31
|
-
e.message
|
|
32
|
-
).render
|
|
33
|
-
rescue JSON::ParserError
|
|
34
|
-
handle_exception($!, request.env)
|
|
35
|
-
raise Committee::InvalidRequest if @raise
|
|
36
|
-
@error_class.new(400, :bad_request, "Request body wasn't valid JSON.").render
|
|
37
35
|
end
|
|
38
36
|
|
|
39
37
|
private
|
|
@@ -379,6 +379,13 @@ describe Committee::Middleware::RequestValidation do
|
|
|
379
379
|
assert_match(/expected integer, but received String: foo/i, last_response.body)
|
|
380
380
|
end
|
|
381
381
|
|
|
382
|
+
it "ignores errors when ignore_error: true" do
|
|
383
|
+
@app = new_rack_app(schema: open_api_3_schema, ignore_error: true)
|
|
384
|
+
get "/characters?limit=foo"
|
|
385
|
+
|
|
386
|
+
assert_equal 200, last_response.status
|
|
387
|
+
end
|
|
388
|
+
|
|
382
389
|
it "coerce string to integer" do
|
|
383
390
|
check_parameter_string = lambda { |env|
|
|
384
391
|
assert env['committee.params']['integer'].is_a?(Integer)
|
|
@@ -429,6 +436,22 @@ describe Committee::Middleware::RequestValidation do
|
|
|
429
436
|
end
|
|
430
437
|
end
|
|
431
438
|
|
|
439
|
+
describe ':accept_request_filter' do
|
|
440
|
+
[
|
|
441
|
+
{ description: 'when not specified, includes everything', accept_request_filter: nil, expected: { status: 400 } },
|
|
442
|
+
{ description: 'when predicate matches, performs validation', accept_request_filter: -> (request) { request.path.start_with?('/v1/c') }, expected: { status: 400 } },
|
|
443
|
+
{ description: 'when predicate does not match, skips validation', accept_request_filter: -> (request) { request.path.start_with?('/v1/x') }, expected: { status: 200 } },
|
|
444
|
+
].each do |description:, accept_request_filter:, expected:|
|
|
445
|
+
it description do
|
|
446
|
+
@app = new_rack_app(prefix: '/v1', schema: open_api_3_schema, accept_request_filter: accept_request_filter)
|
|
447
|
+
|
|
448
|
+
post 'v1/characters', JSON.generate(string_post_1: 1)
|
|
449
|
+
|
|
450
|
+
assert_equal expected[:status], last_response.status
|
|
451
|
+
end
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
|
|
432
455
|
private
|
|
433
456
|
|
|
434
457
|
def new_rack_app(options = {})
|
|
@@ -296,6 +296,16 @@ describe Committee::Middleware::RequestValidation do
|
|
|
296
296
|
assert_match(/invalid request/i, last_response.body)
|
|
297
297
|
end
|
|
298
298
|
|
|
299
|
+
it "ignores errors when ignore_error: true" do
|
|
300
|
+
@app = new_rack_app(schema: hyper_schema, ignore_error: true)
|
|
301
|
+
header "Content-Type", "application/json"
|
|
302
|
+
params = {
|
|
303
|
+
"name" => 1
|
|
304
|
+
}
|
|
305
|
+
post "/apps", JSON.generate(params)
|
|
306
|
+
assert_equal 200, last_response.status
|
|
307
|
+
end
|
|
308
|
+
|
|
299
309
|
it "calls error_handler (has a arg) when request is invalid" do
|
|
300
310
|
called_err = nil
|
|
301
311
|
pr = ->(e) { called_err = e }
|
|
@@ -480,6 +490,22 @@ describe Committee::Middleware::RequestValidation do
|
|
|
480
490
|
assert_equal 200, last_response.status
|
|
481
491
|
end
|
|
482
492
|
|
|
493
|
+
describe ':accept_request_filter' do
|
|
494
|
+
[
|
|
495
|
+
{ description: 'when not specified, includes everything', accept_request_filter: nil, expected: { status: 400 } },
|
|
496
|
+
{ description: 'when predicate matches, performs validation', accept_request_filter: -> (request) { request.path.start_with?('/v1/a') }, expected: { status: 400 } },
|
|
497
|
+
{ description: 'when predicate does not match, skips validation', accept_request_filter: -> (request) { request.path.start_with?('/v1/x') }, expected: { status: 200 } },
|
|
498
|
+
].each do |description:, accept_request_filter:, expected:|
|
|
499
|
+
it description do
|
|
500
|
+
@app = new_rack_app(prefix: '/v1', schema: hyper_schema, accept_request_filter: accept_request_filter)
|
|
501
|
+
|
|
502
|
+
post '/v1/apps', '{x:y}'
|
|
503
|
+
|
|
504
|
+
assert_equal expected[:status], last_response.status
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
end
|
|
508
|
+
|
|
483
509
|
private
|
|
484
510
|
|
|
485
511
|
def new_rack_app(options = {})
|
|
@@ -100,29 +100,41 @@ describe Committee::Middleware::ResponseValidation do
|
|
|
100
100
|
end
|
|
101
101
|
|
|
102
102
|
describe 'check header' do
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
103
|
+
[
|
|
104
|
+
{ check_header: true, description: 'valid value', header: { 'integer' => 1 }, expected: { status: 200 } },
|
|
105
|
+
{ check_header: true, description: 'missing value', header: { 'integer' => nil }, expected: { error: 'headers/integer/schema does not allow null values' } },
|
|
106
|
+
{ check_header: true, description: 'invalid value', header: { 'integer' => 'x' }, expected: { error: 'headers/integer/schema expected integer, but received String: x' } },
|
|
107
|
+
|
|
108
|
+
{ check_header: false, description: 'valid value', header: { 'integer' => 1 }, expected: { status: 200 } },
|
|
109
|
+
{ check_header: false, description: 'missing value', header: { 'integer' => nil }, expected: { status: 200 } },
|
|
110
|
+
{ check_header: false, description: 'invalid value', header: { 'integer' => 'x' }, expected: { status: 200 } },
|
|
111
|
+
].each do |check_header:, description:, header:, expected:|
|
|
112
|
+
describe "when #{check_header}" do
|
|
113
|
+
%w(get post put patch delete).each do |method|
|
|
114
|
+
describe method do
|
|
115
|
+
describe description do
|
|
116
|
+
if expected[:error].nil?
|
|
117
|
+
it 'should pass' do
|
|
118
|
+
@app = new_response_rack({}.to_json, header, schema: open_api_3_schema, raise: true, check_header: check_header)
|
|
119
|
+
|
|
120
|
+
send(method, "/header")
|
|
121
|
+
assert_equal expected[:status], last_response.status
|
|
122
|
+
end
|
|
123
|
+
else
|
|
124
|
+
it 'should fail' do
|
|
125
|
+
@app = new_response_rack({}.to_json, header, schema: open_api_3_schema, raise: true, check_header: check_header)
|
|
126
|
+
|
|
127
|
+
error = assert_raises(Committee::InvalidResponse) do
|
|
128
|
+
get "/header"
|
|
129
|
+
end
|
|
130
|
+
assert_match(expected[:error], error.message)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
116
136
|
end
|
|
117
137
|
end
|
|
118
|
-
|
|
119
|
-
it 'invalid type but not check' do
|
|
120
|
-
@app = new_response_rack({}.to_json, {'x-limit' => '1'}, schema: open_api_3_schema, raise: true, check_header: false)
|
|
121
|
-
|
|
122
|
-
get "/header"
|
|
123
|
-
|
|
124
|
-
assert_equal 200, last_response.status
|
|
125
|
-
end
|
|
126
138
|
end
|
|
127
139
|
|
|
128
140
|
describe 'validate error option' do
|
|
@@ -157,6 +169,22 @@ describe Committee::Middleware::ResponseValidation do
|
|
|
157
169
|
end
|
|
158
170
|
end
|
|
159
171
|
|
|
172
|
+
describe ':accept_request_filter' do
|
|
173
|
+
[
|
|
174
|
+
{ description: 'when not specified, includes everything', accept_request_filter: nil, expected: { status: 500 } },
|
|
175
|
+
{ description: 'when predicate matches, performs validation', accept_request_filter: -> (request) { request.path.start_with?('/v1/c') }, expected: { status: 500 } },
|
|
176
|
+
{ description: 'when predicate does not match, skips validation', accept_request_filter: -> (request) { request.path.start_with?('/v1/x') }, expected: { status: 200 } },
|
|
177
|
+
].each do |description:, accept_request_filter:, expected:|
|
|
178
|
+
it description do
|
|
179
|
+
@app = new_response_rack('not_json', {}, schema: open_api_3_schema, prefix: '/v1', accept_request_filter: accept_request_filter)
|
|
180
|
+
|
|
181
|
+
get 'v1/characters'
|
|
182
|
+
|
|
183
|
+
assert_equal expected[:status], last_response.status
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
160
188
|
private
|
|
161
189
|
|
|
162
190
|
def new_response_rack(response, headers = {}, options = {}, rack_options = {})
|
|
@@ -162,6 +162,22 @@ describe Committee::Middleware::ResponseValidation do
|
|
|
162
162
|
assert_match(/valid JSON/i, last_response.body)
|
|
163
163
|
end
|
|
164
164
|
|
|
165
|
+
describe ':accept_request_filter' do
|
|
166
|
+
[
|
|
167
|
+
{ description: 'when not specified, includes everything', accept_request_filter: nil, expected: { status: 500 } },
|
|
168
|
+
{ description: 'when predicate matches, performs validation', accept_request_filter: -> (request) { request.path.start_with?('/v1/a') }, expected: { status: 500 } },
|
|
169
|
+
{ description: 'when predicate does not match, skips validation', accept_request_filter: -> (request) { request.path.start_with?('/v1/x') }, expected: { status: 200 } },
|
|
170
|
+
].each do |description:, accept_request_filter:, expected:|
|
|
171
|
+
it description do
|
|
172
|
+
@app = new_rack_app('not_json', {}, schema: hyper_schema, prefix: '/v1', accept_request_filter: accept_request_filter)
|
|
173
|
+
|
|
174
|
+
get '/v1/apps'
|
|
175
|
+
|
|
176
|
+
assert_equal expected[:status], last_response.status
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
165
181
|
private
|
|
166
182
|
|
|
167
183
|
def new_rack_app(response, headers = {}, options = {})
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: committee
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brandur
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date: 2019-
|
|
13
|
+
date: 2019-11-15 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: json_schema
|