committee 3.2.0 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/committee/drivers.rb +5 -5
- data/lib/committee/middleware/base.rb +3 -1
- data/lib/committee/middleware/request_validation.rb +17 -19
- data/lib/committee/middleware/response_validation.rb +2 -3
- data/lib/committee/schema_validator/hyper_schema.rb +8 -1
- data/lib/committee/schema_validator/open_api_3.rb +8 -1
- data/lib/committee/schema_validator/open_api_3/operation_wrapper.rb +3 -1
- data/lib/committee/schema_validator/open_api_3/response_validator.rb +0 -1
- data/lib/committee/schema_validator/option.rb +8 -1
- data/test/bin/committee_stub_test.rb +5 -1
- data/test/middleware/base_test.rb +9 -3
- data/test/middleware/request_validation_open_api_3_test.rb +71 -18
- data/test/middleware/request_validation_test.rb +32 -0
- data/test/middleware/response_validation_open_api_3_test.rb +95 -20
- data/test/middleware/response_validation_test.rb +22 -0
- data/test/middleware/stub_test.rb +4 -0
- data/test/request_unpacker_test.rb +12 -3
- data/test/schema_validator/hyper_schema/router_test.rb +4 -0
- data/test/schema_validator/open_api_3/operation_wrapper_test.rb +12 -10
- data/test/schema_validator/open_api_3/request_validator_test.rb +3 -0
- data/test/schema_validator/open_api_3/response_validator_test.rb +8 -3
- data/test/test/methods_new_version_test.rb +3 -0
- data/test/test/methods_test.rb +12 -8
- data/test/test_helper.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43984e56c905ff9e141e1ed49af5c9e51b07c39bda8bc268d195dc5799809d89
|
4
|
+
data.tar.gz: 76a6269ac7cc8237a63b2ae6c69ac512a60cecabaed7564dee88cd3adfa9328e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f79ef24531c7b81489d12ea59e9da42e570236554a84c064c8478625e29167c3fef7245196a2c48d2a0a31ab33639417d47527321b321172f32c5f80fce5f46b
|
7
|
+
data.tar.gz: 68c8ad83aa2392ba1d31d440edb54b1301b6c37e093f7d466c0a9f406510a0efbdf6c9ea8aacf1ddf051fae31c03d2bd777accd90101bd321037dfdafd0affbf
|
data/lib/committee/drivers.rb
CHANGED
@@ -21,14 +21,14 @@ module Committee
|
|
21
21
|
# @param [String] schema_path
|
22
22
|
# @return [Committee::Driver]
|
23
23
|
def self.load_from_json(schema_path)
|
24
|
-
load_from_data(JSON.parse(File.read(schema_path)))
|
24
|
+
load_from_data(JSON.parse(File.read(schema_path)), schema_path)
|
25
25
|
end
|
26
26
|
|
27
27
|
# load and build drive from YAML file
|
28
28
|
# @param [String] schema_path
|
29
29
|
# @return [Committee::Driver]
|
30
30
|
def self.load_from_yaml(schema_path)
|
31
|
-
load_from_data(YAML.load_file(schema_path))
|
31
|
+
load_from_data(YAML.load_file(schema_path), schema_path)
|
32
32
|
end
|
33
33
|
|
34
34
|
# load and build drive from file
|
@@ -48,10 +48,10 @@ module Committee
|
|
48
48
|
# load and build drive from Hash object
|
49
49
|
# @param [Hash] hash
|
50
50
|
# @return [Committee::Driver]
|
51
|
-
def self.load_from_data(hash)
|
51
|
+
def self.load_from_data(hash, schema_path = nil)
|
52
52
|
if hash['openapi']&.start_with?('3.0.')
|
53
|
-
|
54
|
-
return Committee::Drivers::OpenAPI3::Driver.new.parse(
|
53
|
+
openapi = OpenAPIParser.parse_with_filepath(hash, schema_path)
|
54
|
+
return Committee::Drivers::OpenAPI3::Driver.new.parse(openapi)
|
55
55
|
end
|
56
56
|
|
57
57
|
driver = if hash['swagger'] == '2.0'
|
@@ -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
|
@@ -8,13 +8,12 @@ module Committee
|
|
8
8
|
def initialize(app, options = {})
|
9
9
|
super
|
10
10
|
@validate_success_only = @schema.validator_option.validate_success_only
|
11
|
-
@ignore_error = options.fetch(:ignore_error, false)
|
12
11
|
end
|
13
12
|
|
14
13
|
def handle(request)
|
15
|
-
|
16
|
-
status, headers, response = @app.call(request.env)
|
14
|
+
status, headers, response = @app.call(request.env)
|
17
15
|
|
16
|
+
begin
|
18
17
|
v = build_schema_validator(request)
|
19
18
|
v.response_validate(status, headers, response) if v.link_exist? && self.class.validate?(status, validate_success_only)
|
20
19
|
|
@@ -35,7 +35,14 @@ module Committee
|
|
35
35
|
response.each do |chunk|
|
36
36
|
full_body << chunk
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
|
+
data = {}
|
40
|
+
unless full_body.empty?
|
41
|
+
parse_to_json = !validator_option.parse_response_by_content_type ||
|
42
|
+
headers.fetch('Content-Type', nil)&.start_with?('application/json')
|
43
|
+
data = JSON.parse(full_body) if parse_to_json
|
44
|
+
end
|
45
|
+
|
39
46
|
Committee::SchemaValidator::HyperSchema::ResponseValidator.new(link, validate_success_only: validator_option.validate_success_only).call(status, headers, data)
|
40
47
|
end
|
41
48
|
|
@@ -30,7 +30,14 @@ module Committee
|
|
30
30
|
response.each do |chunk|
|
31
31
|
full_body << chunk
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
|
+
parse_to_json = !validator_option.parse_response_by_content_type ||
|
35
|
+
headers.fetch('Content-Type', nil)&.start_with?('application/json')
|
36
|
+
data = if parse_to_json
|
37
|
+
full_body.empty? ? {} : JSON.parse(full_body)
|
38
|
+
else
|
39
|
+
full_body
|
40
|
+
end
|
34
41
|
|
35
42
|
strict = test_method
|
36
43
|
Committee::SchemaValidator::OpenAPI3::ResponseValidator.
|
@@ -116,7 +116,9 @@ module Committee
|
|
116
116
|
content_type = headers['Content-Type'].to_s.split(";").first.to_s
|
117
117
|
|
118
118
|
# bad performance because when we coerce value, same check
|
119
|
-
|
119
|
+
schema_validator_options = build_openapi_parser_post_option(validator_option)
|
120
|
+
request_operation.validate_request_parameter(params, headers, schema_validator_options)
|
121
|
+
request_operation.validate_request_body(content_type, params, schema_validator_options)
|
120
122
|
rescue => e
|
121
123
|
raise Committee::InvalidRequest.new(e.message)
|
122
124
|
end
|
@@ -17,7 +17,6 @@ module Committee
|
|
17
17
|
def call(status, headers, response_data, strict)
|
18
18
|
return unless Committee::Middleware::ResponseValidation.validate?(status, validate_success_only)
|
19
19
|
|
20
|
-
#content_type = headers['Content-Type'].to_s.split(";").first.to_s
|
21
20
|
operation_wrapper.validate_response_params(status, headers, response_data, strict, check_header)
|
22
21
|
end
|
23
22
|
|
@@ -15,7 +15,8 @@ module Committee
|
|
15
15
|
:coerce_query_params,
|
16
16
|
:coerce_recursive,
|
17
17
|
:optimistic_json,
|
18
|
-
:validate_success_only
|
18
|
+
:validate_success_only,
|
19
|
+
:parse_response_by_content_type
|
19
20
|
|
20
21
|
# Non-boolean options:
|
21
22
|
attr_reader :headers_key,
|
@@ -35,6 +36,12 @@ module Committee
|
|
35
36
|
@check_header = options.fetch(:check_header, true)
|
36
37
|
@coerce_recursive = options.fetch(:coerce_recursive, true)
|
37
38
|
@optimistic_json = options.fetch(:optimistic_json, false)
|
39
|
+
@parse_response_by_content_type = if options[:parse_response_by_content_type].nil?
|
40
|
+
Committee.warn_deprecated('Committee: please set parse_response_by_content_type = false because we\'ll change default value in next major version.')
|
41
|
+
false
|
42
|
+
else
|
43
|
+
options.fetch(:parse_response_by_content_type)
|
44
|
+
end
|
38
45
|
|
39
46
|
# Boolean options and have a different value by default
|
40
47
|
@allow_get_body = options.fetch(:allow_get_body, schema.driver.default_allow_get_body)
|
@@ -43,7 +43,11 @@ describe Committee::Bin::CommitteeStub, "app" do
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def app
|
46
|
-
|
46
|
+
options = {}
|
47
|
+
# TODO: delete when 5.0.0 released because default value changed
|
48
|
+
options[:parse_response_by_content_type] = false
|
49
|
+
|
50
|
+
@bin.get_app(hyper_schema, options)
|
47
51
|
end
|
48
52
|
|
49
53
|
it "defaults to a 404" do
|
@@ -103,17 +103,20 @@ describe Committee::Middleware::Base do
|
|
103
103
|
|
104
104
|
describe 'initialize option' do
|
105
105
|
it "schema_path option with hyper-schema" do
|
106
|
-
|
106
|
+
# TODO: delete when 5.0.0 released because default value changed
|
107
|
+
b = Committee::Middleware::Base.new(nil, schema_path: hyper_schema_schema_path, parse_response_by_content_type: false)
|
107
108
|
assert_kind_of Committee::Drivers::HyperSchema::Schema, b.instance_variable_get(:@schema)
|
108
109
|
end
|
109
110
|
|
110
111
|
it "schema_path option with OpenAPI2" do
|
111
|
-
|
112
|
+
# TODO: delete when 5.0.0 released because default value changed
|
113
|
+
b = Committee::Middleware::Base.new(nil, schema_path: open_api_2_schema_path, parse_response_by_content_type: false)
|
112
114
|
assert_kind_of Committee::Drivers::OpenAPI2::Schema, b.instance_variable_get(:@schema)
|
113
115
|
end
|
114
116
|
|
115
117
|
it "schema_path option with OpenAPI3" do
|
116
|
-
|
118
|
+
# TODO: delete when 5.0.0 released because default value changed
|
119
|
+
b = Committee::Middleware::Base.new(nil, schema_path: open_api_3_schema_path, parse_response_by_content_type: false)
|
117
120
|
assert_kind_of Committee::Drivers::OpenAPI3::Schema, b.instance_variable_get(:@schema)
|
118
121
|
end
|
119
122
|
end
|
@@ -121,6 +124,9 @@ describe Committee::Middleware::Base do
|
|
121
124
|
private
|
122
125
|
|
123
126
|
def new_rack_app(options = {})
|
127
|
+
# TODO: delete when 5.0.0 released because default value changed
|
128
|
+
options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
|
129
|
+
|
124
130
|
Rack::Builder.new {
|
125
131
|
use Committee::Middleware::RequestValidation, options
|
126
132
|
run lambda { |_|
|
@@ -249,8 +249,7 @@ describe Committee::Middleware::RequestValidation do
|
|
249
249
|
}
|
250
250
|
post "/characters", JSON.generate(params)
|
251
251
|
assert_equal 400, last_response.status
|
252
|
-
|
253
|
-
assert_match(/1 class is #{1.class}/i, last_response.body)
|
252
|
+
assert_match(/expected string, but received Integer:/i, last_response.body)
|
254
253
|
end
|
255
254
|
|
256
255
|
it "rescues JSON errors" do
|
@@ -279,7 +278,7 @@ describe Committee::Middleware::RequestValidation do
|
|
279
278
|
header "Content-Type", "application/json"
|
280
279
|
post "/v1/characters", JSON.generate(params)
|
281
280
|
assert_equal 400, last_response.status
|
282
|
-
assert_match(/
|
281
|
+
assert_match(/expected string, but received Integer: /i, last_response.body)
|
283
282
|
end
|
284
283
|
|
285
284
|
it "ignores paths outside the prefix" do
|
@@ -321,7 +320,7 @@ describe Committee::Middleware::RequestValidation do
|
|
321
320
|
get "/validate", nil
|
322
321
|
end
|
323
322
|
|
324
|
-
assert_match(/required parameters query_string
|
323
|
+
assert_match(/missing required parameters: query_string/i, e.message)
|
325
324
|
end
|
326
325
|
|
327
326
|
it "raises error when required path parameter is invalid" do
|
@@ -332,7 +331,7 @@ describe Committee::Middleware::RequestValidation do
|
|
332
331
|
get "/coerce_path_params/#{not_an_integer}", nil
|
333
332
|
end
|
334
333
|
|
335
|
-
assert_match(/
|
334
|
+
assert_match(/expected integer, but received String: abc/i, e.message)
|
336
335
|
end
|
337
336
|
|
338
337
|
it "optionally raises an error" do
|
@@ -356,7 +355,7 @@ describe Committee::Middleware::RequestValidation do
|
|
356
355
|
get "/string_params_coercer", {"integer_1" => "1"}
|
357
356
|
|
358
357
|
assert_equal 400, last_response.status
|
359
|
-
assert_match(/
|
358
|
+
assert_match(/expected integer, but received String:/i, last_response.body)
|
360
359
|
end
|
361
360
|
|
362
361
|
it "passes through a valid request for OpenAPI3" do
|
@@ -375,7 +374,14 @@ describe Committee::Middleware::RequestValidation do
|
|
375
374
|
get "/characters?limit=foo"
|
376
375
|
|
377
376
|
assert_equal 400, last_response.status
|
378
|
-
assert_match(/foo
|
377
|
+
assert_match(/expected integer, but received String: foo/i, last_response.body)
|
378
|
+
end
|
379
|
+
|
380
|
+
it "ignores errors when ignore_error: true" do
|
381
|
+
@app = new_rack_app(schema: open_api_3_schema, ignore_error: true)
|
382
|
+
get "/characters?limit=foo"
|
383
|
+
|
384
|
+
assert_equal 200, last_response.status
|
379
385
|
end
|
380
386
|
|
381
387
|
it "coerce string to integer" do
|
@@ -399,21 +405,65 @@ describe Committee::Middleware::RequestValidation do
|
|
399
405
|
end
|
400
406
|
|
401
407
|
describe 'check header' do
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
408
|
+
[
|
409
|
+
{ check_header: true, description: 'valid value', value: 1, expected: { status: 200 } },
|
410
|
+
{ check_header: true, description: 'missing value', value: nil, expected: { status: 400, error: 'missing required parameters: integer' } },
|
411
|
+
{ check_header: true, description: 'invalid value', value: 'x', expected: { status: 400, error: 'expected integer, but received String: x' } },
|
412
|
+
|
413
|
+
{ check_header: false, description: 'valid value', value: 1, expected: { status: 200 } },
|
414
|
+
{ check_header: false, description: 'missing value', value: nil, expected: { status: 200 } },
|
415
|
+
{ check_header: false, description: 'invalid value', value: 'x', expected: { status: 200 } },
|
416
|
+
].each do |h|
|
417
|
+
check_header = h[:check_header]
|
418
|
+
description = h[:description]
|
419
|
+
value = h[:value]
|
420
|
+
expected = h[:expected]
|
421
|
+
describe "when #{check_header}" do
|
422
|
+
%w(get post put patch delete).each do |method|
|
423
|
+
describe method do
|
424
|
+
describe description do
|
425
|
+
it (expected[:error].nil? ? 'should pass' : 'should fail') do
|
426
|
+
@app = new_rack_app(schema: open_api_3_schema, check_header: check_header)
|
427
|
+
|
428
|
+
header 'integer', value
|
429
|
+
send(method, "/header")
|
430
|
+
|
431
|
+
assert_equal expected[:status], last_response.status
|
432
|
+
assert_match(expected[:error], last_response.body) if expected[:error]
|
433
|
+
end
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|
437
|
+
end
|
409
438
|
end
|
439
|
+
end
|
410
440
|
|
411
|
-
|
412
|
-
|
441
|
+
describe ':accept_request_filter' do
|
442
|
+
[
|
443
|
+
{ description: 'when not specified, includes everything', accept_request_filter: nil, expected: { status: 400 } },
|
444
|
+
{ description: 'when predicate matches, performs validation', accept_request_filter: -> (request) { request.path.start_with?('/v1/c') }, expected: { status: 400 } },
|
445
|
+
{ description: 'when predicate does not match, skips validation', accept_request_filter: -> (request) { request.path.start_with?('/v1/x') }, expected: { status: 200 } },
|
446
|
+
].each do |h|
|
447
|
+
description = h[:description]
|
448
|
+
accept_request_filter = h[:accept_request_filter]
|
449
|
+
expected = h[:expected]
|
450
|
+
it description do
|
451
|
+
@app = new_rack_app(prefix: '/v1', schema: open_api_3_schema, accept_request_filter: accept_request_filter)
|
452
|
+
|
453
|
+
post 'v1/characters', JSON.generate(string_post_1: 1)
|
454
|
+
|
455
|
+
assert_equal expected[:status], last_response.status
|
456
|
+
end
|
457
|
+
end
|
458
|
+
end
|
413
459
|
|
414
|
-
|
460
|
+
it 'does not suppress application error' do
|
461
|
+
@app = new_rack_app_with_lambda(lambda { |_|
|
462
|
+
JSON.load('-') # invalid json
|
463
|
+
}, schema: open_api_3_schema, raise: true)
|
415
464
|
|
416
|
-
|
465
|
+
assert_raises(JSON::ParserError) do
|
466
|
+
get "/error", nil
|
417
467
|
end
|
418
468
|
end
|
419
469
|
|
@@ -426,6 +476,9 @@ describe Committee::Middleware::RequestValidation do
|
|
426
476
|
end
|
427
477
|
|
428
478
|
def new_rack_app_with_lambda(check_lambda, options = {})
|
479
|
+
# TODO: delete when 5.0.0 released because default value changed
|
480
|
+
options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
|
481
|
+
|
429
482
|
Rack::Builder.new {
|
430
483
|
use Committee::Middleware::RequestValidation, options
|
431
484
|
run check_lambda
|
@@ -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,25 @@ 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 |h|
|
499
|
+
description = h[:description]
|
500
|
+
accept_request_filter = h[:accept_request_filter]
|
501
|
+
expected = h[:expected]
|
502
|
+
it description do
|
503
|
+
@app = new_rack_app(prefix: '/v1', schema: hyper_schema, accept_request_filter: accept_request_filter)
|
504
|
+
|
505
|
+
post '/v1/apps', '{x:y}'
|
506
|
+
|
507
|
+
assert_equal expected[:status], last_response.status
|
508
|
+
end
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
483
512
|
private
|
484
513
|
|
485
514
|
def new_rack_app(options = {})
|
@@ -490,6 +519,9 @@ describe Committee::Middleware::RequestValidation do
|
|
490
519
|
|
491
520
|
|
492
521
|
def new_rack_app_with_lambda(check_lambda, options = {})
|
522
|
+
# TODO: delete when 5.0.0 released because default value changed
|
523
|
+
options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
|
524
|
+
|
493
525
|
Rack::Builder.new {
|
494
526
|
use Committee::Middleware::RequestValidation, options
|
495
527
|
run check_lambda
|
@@ -34,6 +34,14 @@ describe Committee::Middleware::ResponseValidation do
|
|
34
34
|
assert_equal 200, last_response.status
|
35
35
|
end
|
36
36
|
|
37
|
+
it "passes through a invalid json with parse_response_by_content_type option" do
|
38
|
+
@app = new_response_rack("csv response", { "Content-Type" => "test/csv"}, schema: open_api_3_schema, parse_response_by_content_type: true)
|
39
|
+
|
40
|
+
get "/csv"
|
41
|
+
|
42
|
+
assert_equal 200, last_response.status
|
43
|
+
end
|
44
|
+
|
37
45
|
it "passes through not definition" do
|
38
46
|
@app = new_response_rack(JSON.generate(CHARACTERS_RESPONSE), {}, schema: open_api_3_schema)
|
39
47
|
get "/no_data"
|
@@ -47,7 +55,7 @@ describe Committee::Middleware::ResponseValidation do
|
|
47
55
|
get "/characters"
|
48
56
|
}
|
49
57
|
|
50
|
-
assert_match(/
|
58
|
+
assert_match(/expected object, but received Array: /i, e.message)
|
51
59
|
end
|
52
60
|
|
53
61
|
it "passes through a 204 (no content) response" do
|
@@ -99,29 +107,59 @@ describe Committee::Middleware::ResponseValidation do
|
|
99
107
|
assert_match(/valid JSON/i, last_response.body)
|
100
108
|
end
|
101
109
|
|
102
|
-
describe
|
103
|
-
it
|
104
|
-
@app = new_response_rack(
|
105
|
-
|
106
|
-
get "/header"
|
107
|
-
|
110
|
+
describe "remote schema $ref" do
|
111
|
+
it "passes through a valid response" do
|
112
|
+
@app = new_response_rack(JSON.generate({ "sample" => "value" }), {}, schema: open_api_3_schema)
|
113
|
+
get "/ref-sample"
|
108
114
|
assert_equal 200, last_response.status
|
109
115
|
end
|
110
116
|
|
111
|
-
it
|
112
|
-
@app = new_response_rack({}
|
113
|
-
|
114
|
-
|
115
|
-
get "/header"
|
116
|
-
end
|
117
|
+
it "detects a invalid response" do
|
118
|
+
@app = new_response_rack("{}", {}, schema: open_api_3_schema)
|
119
|
+
get "/ref-sample"
|
120
|
+
assert_equal 500, last_response.status
|
117
121
|
end
|
122
|
+
end
|
118
123
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
124
|
+
describe 'check header' do
|
125
|
+
[
|
126
|
+
{ check_header: true, description: 'valid value', header: { 'integer' => 1 }, expected: { status: 200 } },
|
127
|
+
{ check_header: true, description: 'missing value', header: { 'integer' => nil }, expected: { error: 'headers/integer/schema does not allow null values' } },
|
128
|
+
{ check_header: true, description: 'invalid value', header: { 'integer' => 'x' }, expected: { error: 'headers/integer/schema expected integer, but received String: x' } },
|
129
|
+
|
130
|
+
{ check_header: false, description: 'valid value', header: { 'integer' => 1 }, expected: { status: 200 } },
|
131
|
+
{ check_header: false, description: 'missing value', header: { 'integer' => nil }, expected: { status: 200 } },
|
132
|
+
{ check_header: false, description: 'invalid value', header: { 'integer' => 'x' }, expected: { status: 200 } },
|
133
|
+
].each do |h|
|
134
|
+
check_header = h[:check_header]
|
135
|
+
description = h[:description]
|
136
|
+
header = h[:header]
|
137
|
+
expected = h[:expected]
|
138
|
+
describe "when #{check_header}" do
|
139
|
+
%w(get post put patch delete).each do |method|
|
140
|
+
describe method do
|
141
|
+
describe description do
|
142
|
+
if expected[:error].nil?
|
143
|
+
it 'should pass' do
|
144
|
+
@app = new_response_rack({}.to_json, header, schema: open_api_3_schema, raise: true, check_header: check_header)
|
145
|
+
|
146
|
+
send(method, "/header")
|
147
|
+
assert_equal expected[:status], last_response.status
|
148
|
+
end
|
149
|
+
else
|
150
|
+
it 'should fail' do
|
151
|
+
@app = new_response_rack({}.to_json, header, schema: open_api_3_schema, raise: true, check_header: check_header)
|
152
|
+
|
153
|
+
error = assert_raises(Committee::InvalidResponse) do
|
154
|
+
get "/header"
|
155
|
+
end
|
156
|
+
assert_match(expected[:error], error.message)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
125
163
|
end
|
126
164
|
end
|
127
165
|
|
@@ -138,7 +176,8 @@ describe Committee::Middleware::ResponseValidation do
|
|
138
176
|
e = assert_raises(Committee::InvalidResponse) do
|
139
177
|
get "/characters"
|
140
178
|
end
|
141
|
-
|
179
|
+
|
180
|
+
assert_match(/but received String: 1/i, e.message)
|
142
181
|
end
|
143
182
|
|
144
183
|
it "detects an invalid response status code with validate_success_only=true" do
|
@@ -156,9 +195,45 @@ describe Committee::Middleware::ResponseValidation do
|
|
156
195
|
end
|
157
196
|
end
|
158
197
|
|
198
|
+
describe ':accept_request_filter' do
|
199
|
+
[
|
200
|
+
{ description: 'when not specified, includes everything', accept_request_filter: nil, expected: { status: 500 } },
|
201
|
+
{ description: 'when predicate matches, performs validation', accept_request_filter: -> (request) { request.path.start_with?('/v1/c') }, expected: { status: 500 } },
|
202
|
+
{ description: 'when predicate does not match, skips validation', accept_request_filter: -> (request) { request.path.start_with?('/v1/x') }, expected: { status: 200 } },
|
203
|
+
].each do |h|
|
204
|
+
description = h[:description]
|
205
|
+
accept_request_filter = h[:accept_request_filter]
|
206
|
+
expected = h[:expected]
|
207
|
+
|
208
|
+
it description do
|
209
|
+
@app = new_response_rack('not_json', {}, schema: open_api_3_schema, prefix: '/v1', accept_request_filter: accept_request_filter)
|
210
|
+
|
211
|
+
get 'v1/characters'
|
212
|
+
|
213
|
+
assert_equal expected[:status], last_response.status
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
it 'does not suppress application error' do
|
219
|
+
@app = Rack::Builder.new {
|
220
|
+
use Committee::Middleware::ResponseValidation, {schema: open_api_3_schema, raise: true}
|
221
|
+
run lambda { |_|
|
222
|
+
JSON.load('-') # invalid json
|
223
|
+
}
|
224
|
+
}
|
225
|
+
|
226
|
+
assert_raises(JSON::ParserError) do
|
227
|
+
get "/error", nil
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
159
231
|
private
|
160
232
|
|
161
233
|
def new_response_rack(response, headers = {}, options = {}, rack_options = {})
|
234
|
+
# TODO: delete when 5.0.0 released because default value changed
|
235
|
+
options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
|
236
|
+
|
162
237
|
status = rack_options[:status] || 200
|
163
238
|
headers = {
|
164
239
|
"Content-Type" => "application/json"
|
@@ -162,9 +162,31 @@ 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 |h|
|
171
|
+
description = h[:description]
|
172
|
+
accept_request_filter = h[:accept_request_filter]
|
173
|
+
expected = h[:expected]
|
174
|
+
it description do
|
175
|
+
@app = new_rack_app('not_json', {}, schema: hyper_schema, prefix: '/v1', accept_request_filter: accept_request_filter)
|
176
|
+
|
177
|
+
get '/v1/apps'
|
178
|
+
|
179
|
+
assert_equal expected[:status], last_response.status
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
165
184
|
private
|
166
185
|
|
167
186
|
def new_rack_app(response, headers = {}, options = {})
|
187
|
+
# TODO: delete when 5.0.0 released because default value changed
|
188
|
+
options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
|
189
|
+
|
168
190
|
headers = {
|
169
191
|
"Content-Type" => "application/json"
|
170
192
|
}.merge(headers)
|
@@ -112,6 +112,10 @@ describe Committee::Middleware::Stub do
|
|
112
112
|
def new_rack_app(options = {})
|
113
113
|
response = options.delete(:response)
|
114
114
|
suppress = options.delete(:suppress)
|
115
|
+
|
116
|
+
# TODO: delete when 5.0.0 released because default value changed
|
117
|
+
options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
|
118
|
+
|
115
119
|
Rack::Builder.new {
|
116
120
|
use Committee::Middleware::Stub, options
|
117
121
|
run lambda { |env|
|
@@ -100,7 +100,10 @@ describe Committee::RequestUnpacker do
|
|
100
100
|
}
|
101
101
|
request = Rack::Request.new(env)
|
102
102
|
|
103
|
-
|
103
|
+
options = {}
|
104
|
+
# TODO: delete when 5.0.0 released because default value changed
|
105
|
+
options[:parse_response_by_content_type] = false
|
106
|
+
router = hyper_schema.build_router(options)
|
104
107
|
validator = router.build_schema_validator(request)
|
105
108
|
|
106
109
|
schema = JsonSchema::Schema.new
|
@@ -133,7 +136,10 @@ describe Committee::RequestUnpacker do
|
|
133
136
|
}
|
134
137
|
request = Rack::Request.new(env)
|
135
138
|
|
136
|
-
|
139
|
+
options = {}
|
140
|
+
# TODO: delete when 5.0.0 released because default value changed
|
141
|
+
options[:parse_response_by_content_type] = false
|
142
|
+
router = open_api_3_schema.build_router(options)
|
137
143
|
validator = router.build_schema_validator(request)
|
138
144
|
|
139
145
|
params, _ = Committee::RequestUnpacker.new(
|
@@ -158,7 +164,10 @@ describe Committee::RequestUnpacker do
|
|
158
164
|
}
|
159
165
|
request = Rack::Request.new(env)
|
160
166
|
|
161
|
-
|
167
|
+
options = {}
|
168
|
+
# TODO: delete when 5.0.0 released because default value changed
|
169
|
+
options[:parse_response_by_content_type] = false
|
170
|
+
router = open_api_3_schema.build_router(options)
|
162
171
|
validator = router.build_schema_validator(request)
|
163
172
|
|
164
173
|
params, _ = Committee::RequestUnpacker.new(
|
@@ -69,6 +69,8 @@ describe Committee::SchemaValidator::HyperSchema::Router do
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def hyper_schema_router(options = {})
|
72
|
+
# TODO: delete when 5.0.0 released because default value changed
|
73
|
+
options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
|
72
74
|
schema = Committee::Drivers::HyperSchema::Driver.new.parse(hyper_schema_data)
|
73
75
|
validator_option = Committee::SchemaValidator::Option.new(options, schema, :hyper_schema)
|
74
76
|
|
@@ -76,6 +78,8 @@ describe Committee::SchemaValidator::HyperSchema::Router do
|
|
76
78
|
end
|
77
79
|
|
78
80
|
def open_api_2_router(options = {})
|
81
|
+
# TODO: delete when 5.0.0 released because default value changed
|
82
|
+
options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
|
79
83
|
schema = Committee::Drivers::OpenAPI2::Driver.new.parse(open_api_2_data)
|
80
84
|
validator_option = Committee::SchemaValidator::Option.new(options, schema, :hyper_schema)
|
81
85
|
|
@@ -9,7 +9,12 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
|
|
9
9
|
before do
|
10
10
|
@path = '/validate'
|
11
11
|
@method = 'post'
|
12
|
-
|
12
|
+
|
13
|
+
# TODO: delete when 5.0.0 released because default value changed
|
14
|
+
options = {}
|
15
|
+
options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
|
16
|
+
|
17
|
+
@validator_option = Committee::SchemaValidator::Option.new(options, open_api_3_schema, :open_api_3)
|
13
18
|
end
|
14
19
|
|
15
20
|
def operation_object
|
@@ -52,8 +57,7 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
|
|
52
57
|
operation_object.validate_request_params({"string" => 1}, HEADER, @validator_option)
|
53
58
|
}
|
54
59
|
|
55
|
-
|
56
|
-
assert e.message.start_with?("1 class is #{1.class} but it's not valid")
|
60
|
+
assert_match(/expected string, but received Integer: 1/i, e.message)
|
57
61
|
end
|
58
62
|
|
59
63
|
it 'support put method' do
|
@@ -64,8 +68,7 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
|
|
64
68
|
operation_object.validate_request_params({"string" => 1}, HEADER, @validator_option)
|
65
69
|
}
|
66
70
|
|
67
|
-
|
68
|
-
assert e.message.start_with?("1 class is #{1.class} but it's not valid")
|
71
|
+
assert_match(/expected string, but received Integer: 1/i, e.message)
|
69
72
|
end
|
70
73
|
|
71
74
|
it 'support patch method' do
|
@@ -76,7 +79,7 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
|
|
76
79
|
operation_object.validate_request_params({"integer" => "str"}, HEADER, @validator_option)
|
77
80
|
}
|
78
81
|
|
79
|
-
|
82
|
+
assert_match(/expected integer, but received String: str/i, e.message)
|
80
83
|
end
|
81
84
|
|
82
85
|
it 'unknown param' do
|
@@ -109,7 +112,7 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
|
|
109
112
|
operation_object.validate_request_params({"query_integer_list" => [1, 2]}, HEADER, @validator_option)
|
110
113
|
}
|
111
114
|
|
112
|
-
|
115
|
+
assert_match(/missing required parameters: query_string/i, e.message)
|
113
116
|
end
|
114
117
|
|
115
118
|
it 'invalid type' do
|
@@ -121,8 +124,7 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
|
|
121
124
|
)
|
122
125
|
}
|
123
126
|
|
124
|
-
|
125
|
-
assert e.message.start_with?("1 class is #{1.class} but")
|
127
|
+
assert_match(/expected string, but received Integer: 1/i, e.message)
|
126
128
|
end
|
127
129
|
end
|
128
130
|
|
@@ -143,7 +145,7 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
|
|
143
145
|
operation_object.validate_request_params({"limit" => "a"}, HEADER, @validator_option)
|
144
146
|
}
|
145
147
|
|
146
|
-
|
148
|
+
assert_match(/expected integer, but received String: a/i, e.message)
|
147
149
|
end
|
148
150
|
end
|
149
151
|
|
@@ -72,6 +72,9 @@ describe Committee::SchemaValidator::OpenAPI3::RequestValidator do
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def new_rack_app(options = {})
|
75
|
+
# TODO: delete when 5.0.0 released because default value changed
|
76
|
+
options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
|
77
|
+
|
75
78
|
Rack::Builder.new {
|
76
79
|
use Committee::Middleware::RequestValidation, options
|
77
80
|
run lambda { |_|
|
@@ -12,7 +12,12 @@ describe Committee::SchemaValidator::OpenAPI3::ResponseValidator do
|
|
12
12
|
|
13
13
|
@path = '/validate'
|
14
14
|
@method = 'post'
|
15
|
-
|
15
|
+
|
16
|
+
# TODO: delete when 5.0.0 released because default value changed
|
17
|
+
options = {}
|
18
|
+
options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
|
19
|
+
|
20
|
+
@validator_option = Committee::SchemaValidator::Option.new(options, open_api_3_schema, :open_api_3)
|
16
21
|
end
|
17
22
|
|
18
23
|
it "passes through a valid response" do
|
@@ -29,7 +34,7 @@ describe Committee::SchemaValidator::OpenAPI3::ResponseValidator do
|
|
29
34
|
call_response_validator
|
30
35
|
end
|
31
36
|
|
32
|
-
it "
|
37
|
+
it "raises InvalidResponse when a valid response with no registered body with strict option" do
|
33
38
|
@headers = { "Content-Type" => "application/xml" }
|
34
39
|
assert_raises(Committee::InvalidResponse) {
|
35
40
|
call_response_validator(true)
|
@@ -41,7 +46,7 @@ describe Committee::SchemaValidator::OpenAPI3::ResponseValidator do
|
|
41
46
|
call_response_validator
|
42
47
|
end
|
43
48
|
|
44
|
-
it "
|
49
|
+
it "raises InvalidResponse when a valid response with no Content-Type headers with strict option" do
|
45
50
|
@headers = {}
|
46
51
|
assert_raises(Committee::InvalidResponse) {
|
47
52
|
call_response_validator(true)
|
@@ -30,6 +30,9 @@ describe Committee::Test::Methods do
|
|
30
30
|
@committee_schema = nil
|
31
31
|
|
32
32
|
@committee_options = {schema: hyper_schema}
|
33
|
+
|
34
|
+
# TODO: delete when 5.0.0 released because default value changed
|
35
|
+
@committee_options[:parse_response_by_content_type] = false
|
33
36
|
end
|
34
37
|
|
35
38
|
describe "#assert_schema_conform" do
|
data/test/test/methods_test.rb
CHANGED
@@ -28,7 +28,10 @@ describe Committee::Test::Methods do
|
|
28
28
|
# our purposes here in testing the module.
|
29
29
|
@committee_router = nil
|
30
30
|
@committee_schema = nil
|
31
|
-
@committee_options =
|
31
|
+
@committee_options = {}
|
32
|
+
|
33
|
+
# TODO: delete when 5.0.0 released because default value changed
|
34
|
+
@committee_options[:parse_response_by_content_type] = true
|
32
35
|
end
|
33
36
|
|
34
37
|
describe "Hyper-Schema" do
|
@@ -36,7 +39,7 @@ describe Committee::Test::Methods do
|
|
36
39
|
sc = JsonSchema.parse!(hyper_schema_data)
|
37
40
|
sc.expand_references!
|
38
41
|
s = Committee::Drivers::HyperSchema::Driver.new.parse(sc)
|
39
|
-
@committee_options
|
42
|
+
@committee_options.merge!({schema: s})
|
40
43
|
end
|
41
44
|
|
42
45
|
describe "#assert_schema_conform" do
|
@@ -120,7 +123,7 @@ describe Committee::Test::Methods do
|
|
120
123
|
|
121
124
|
describe "OpenAPI3" do
|
122
125
|
before do
|
123
|
-
@committee_options
|
126
|
+
@committee_options.merge!({schema: open_api_3_schema})
|
124
127
|
|
125
128
|
@correct_response = { string_1: :honoka }
|
126
129
|
end
|
@@ -138,7 +141,7 @@ describe Committee::Test::Methods do
|
|
138
141
|
e = assert_raises(Committee::InvalidResponse) do
|
139
142
|
assert_schema_conform
|
140
143
|
end
|
141
|
-
assert_match(/
|
144
|
+
assert_match(/response definition does not exist/i, e.message)
|
142
145
|
end
|
143
146
|
|
144
147
|
it "detects an invalid response status code" do
|
@@ -149,7 +152,7 @@ describe Committee::Test::Methods do
|
|
149
152
|
e = assert_raises(Committee::InvalidResponse) do
|
150
153
|
assert_schema_conform
|
151
154
|
end
|
152
|
-
assert_match(/
|
155
|
+
assert_match(/status code definition does not exist/i, e.message)
|
153
156
|
end
|
154
157
|
|
155
158
|
it "outputs deprecation warning" do
|
@@ -175,7 +178,8 @@ describe Committee::Test::Methods do
|
|
175
178
|
e = assert_raises(Committee::InvalidRequest) do
|
176
179
|
assert_request_schema_confirm
|
177
180
|
end
|
178
|
-
|
181
|
+
|
182
|
+
assert_match(/missing required parameters: query_string/i, e.message)
|
179
183
|
end
|
180
184
|
|
181
185
|
it "path undefined in schema" do
|
@@ -201,7 +205,7 @@ describe Committee::Test::Methods do
|
|
201
205
|
e = assert_raises(Committee::InvalidResponse) do
|
202
206
|
assert_response_schema_confirm
|
203
207
|
end
|
204
|
-
assert_match(/
|
208
|
+
assert_match(/response definition does not exist/i, e.message)
|
205
209
|
end
|
206
210
|
|
207
211
|
it "detects an invalid response status code" do
|
@@ -212,7 +216,7 @@ describe Committee::Test::Methods do
|
|
212
216
|
e = assert_raises(Committee::InvalidResponse) do
|
213
217
|
assert_response_schema_confirm
|
214
218
|
end
|
215
|
-
assert_match(/
|
219
|
+
assert_match(/status code definition does not exist/i, e.message)
|
216
220
|
end
|
217
221
|
|
218
222
|
it "path undefined in schema" do
|
data/test/test_helper.rb
CHANGED
@@ -56,7 +56,7 @@ def open_api_2_schema
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def open_api_3_schema
|
59
|
-
@open_api_3_schema ||= Committee::Drivers.
|
59
|
+
@open_api_3_schema ||= Committee::Drivers.load_from_file(open_api_3_schema_path)
|
60
60
|
end
|
61
61
|
|
62
62
|
# Don't cache this because we'll often manipulate the created hash in tests.
|
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:
|
4
|
+
version: 4.2.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:
|
13
|
+
date: 2020-08-26 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: json_schema
|
@@ -52,14 +52,14 @@ dependencies:
|
|
52
52
|
requirements:
|
53
53
|
- - ">="
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: 0.
|
55
|
+
version: 0.11.1
|
56
56
|
type: :runtime
|
57
57
|
prerelease: false
|
58
58
|
version_requirements: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
60
|
- - ">="
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version: 0.
|
62
|
+
version: 0.11.1
|
63
63
|
- !ruby/object:Gem::Dependency
|
64
64
|
name: minitest
|
65
65
|
requirement: !ruby/object:Gem::Requirement
|
@@ -282,14 +282,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
282
282
|
requirements:
|
283
283
|
- - ">="
|
284
284
|
- !ruby/object:Gem::Version
|
285
|
-
version: 2.
|
285
|
+
version: 2.4.0
|
286
286
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
287
287
|
requirements:
|
288
288
|
- - ">="
|
289
289
|
- !ruby/object:Gem::Version
|
290
290
|
version: '0'
|
291
291
|
requirements: []
|
292
|
-
rubygems_version: 3.
|
292
|
+
rubygems_version: 3.1.2
|
293
293
|
signing_key:
|
294
294
|
specification_version: 4
|
295
295
|
summary: A collection of Rack middleware to support JSON Schema.
|