committee 3.1.0 → 3.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/committee-stub +1 -0
- data/lib/committee.rb +12 -34
- data/lib/committee/bin/committee_stub.rb +6 -4
- data/lib/committee/drivers.rb +15 -67
- data/lib/committee/drivers/driver.rb +47 -0
- data/lib/committee/drivers/hyper_schema.rb +8 -171
- data/lib/committee/drivers/hyper_schema/driver.rb +105 -0
- data/lib/committee/drivers/hyper_schema/link.rb +68 -0
- data/lib/committee/drivers/hyper_schema/schema.rb +22 -0
- data/lib/committee/drivers/open_api_2.rb +9 -416
- data/lib/committee/drivers/open_api_2/driver.rb +253 -0
- data/lib/committee/drivers/open_api_2/header_schema_builder.rb +33 -0
- data/lib/committee/drivers/open_api_2/link.rb +36 -0
- data/lib/committee/drivers/open_api_2/parameter_schema_builder.rb +83 -0
- data/lib/committee/drivers/open_api_2/schema.rb +26 -0
- data/lib/committee/drivers/open_api_2/schema_builder.rb +33 -0
- data/lib/committee/drivers/open_api_3.rb +7 -75
- data/lib/committee/drivers/open_api_3/driver.rb +51 -0
- data/lib/committee/drivers/open_api_3/schema.rb +41 -0
- data/lib/committee/drivers/schema.rb +23 -0
- data/lib/committee/errors.rb +2 -0
- data/lib/committee/middleware.rb +11 -0
- data/lib/committee/middleware/base.rb +38 -34
- data/lib/committee/middleware/request_validation.rb +51 -30
- data/lib/committee/middleware/response_validation.rb +49 -26
- data/lib/committee/middleware/stub.rb +55 -51
- data/lib/committee/request_unpacker.rb +3 -1
- data/lib/committee/schema_validator.rb +23 -0
- data/lib/committee/schema_validator/hyper_schema.rb +85 -74
- data/lib/committee/schema_validator/hyper_schema/parameter_coercer.rb +60 -54
- data/lib/committee/schema_validator/hyper_schema/request_validator.rb +43 -37
- data/lib/committee/schema_validator/hyper_schema/response_generator.rb +86 -80
- data/lib/committee/schema_validator/hyper_schema/response_validator.rb +65 -59
- data/lib/committee/schema_validator/hyper_schema/router.rb +35 -29
- data/lib/committee/schema_validator/hyper_schema/string_params_coercer.rb +87 -81
- data/lib/committee/schema_validator/open_api_3.rb +71 -61
- data/lib/committee/schema_validator/open_api_3/operation_wrapper.rb +121 -115
- data/lib/committee/schema_validator/open_api_3/request_validator.rb +24 -18
- data/lib/committee/schema_validator/open_api_3/response_validator.rb +22 -16
- data/lib/committee/schema_validator/open_api_3/router.rb +30 -24
- data/lib/committee/schema_validator/option.rb +42 -38
- data/lib/committee/test/methods.rb +55 -51
- data/lib/committee/validation_error.rb +2 -0
- data/test/bin/committee_stub_test.rb +3 -1
- data/test/bin_test.rb +3 -1
- data/test/committee_test.rb +3 -1
- data/test/drivers/hyper_schema/driver_test.rb +49 -0
- data/test/drivers/{hyper_schema_test.rb → hyper_schema/link_test.rb} +2 -45
- data/test/drivers/open_api_2/driver_test.rb +156 -0
- data/test/drivers/open_api_2/header_schema_builder_test.rb +26 -0
- data/test/drivers/open_api_2/link_test.rb +52 -0
- data/test/drivers/open_api_2/parameter_schema_builder_test.rb +195 -0
- data/test/drivers/{open_api_3_test.rb → open_api_3/driver_test.rb} +5 -3
- data/test/drivers_test.rb +12 -10
- data/test/middleware/base_test.rb +3 -1
- data/test/middleware/request_validation_open_api_3_test.rb +4 -2
- data/test/middleware/request_validation_test.rb +46 -5
- data/test/middleware/response_validation_open_api_3_test.rb +3 -1
- data/test/middleware/response_validation_test.rb +39 -4
- data/test/middleware/stub_test.rb +3 -1
- data/test/request_unpacker_test.rb +2 -2
- data/test/schema_validator/hyper_schema/parameter_coercer_test.rb +2 -2
- data/test/schema_validator/hyper_schema/request_validator_test.rb +3 -1
- data/test/schema_validator/hyper_schema/response_generator_test.rb +3 -1
- data/test/schema_validator/hyper_schema/response_validator_test.rb +3 -1
- data/test/schema_validator/hyper_schema/router_test.rb +5 -3
- data/test/schema_validator/hyper_schema/string_params_coercer_test.rb +3 -1
- data/test/schema_validator/open_api_3/operation_wrapper_test.rb +3 -1
- data/test/schema_validator/open_api_3/request_validator_test.rb +11 -1
- data/test/schema_validator/open_api_3/response_validator_test.rb +3 -1
- data/test/test/methods_new_version_test.rb +3 -1
- data/test/test/methods_test.rb +4 -2
- data/test/test_helper.rb +16 -16
- data/test/validation_error_test.rb +3 -1
- metadata +52 -6
- data/lib/committee/schema_validator/schema_validator.rb +0 -15
- data/test/drivers/open_api_2_test.rb +0 -416
@@ -1,27 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Committee
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
module SchemaValidator
|
5
|
+
class OpenAPI3
|
6
|
+
class RequestValidator
|
7
|
+
# @param [SchemaValidator::OpenAPI3::OperationWrapper] operation_object
|
8
|
+
# @param [Committee::SchemaValidator::Option] validator_option
|
9
|
+
def initialize(operation_object, validator_option:)
|
10
|
+
@operation_object = operation_object
|
11
|
+
@validator_option = validator_option
|
12
|
+
end
|
9
13
|
|
10
|
-
|
11
|
-
|
12
|
-
|
14
|
+
def call(request, params, headers)
|
15
|
+
content_type = ::Committee::SchemaValidator.request_media_type(request)
|
16
|
+
check_content_type(request, content_type) if @validator_option.check_content_type
|
13
17
|
|
14
|
-
|
15
|
-
|
18
|
+
@operation_object.validate_request_params(params, headers, @validator_option)
|
19
|
+
end
|
16
20
|
|
17
|
-
|
21
|
+
private
|
18
22
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
+
def check_content_type(request, content_type)
|
24
|
+
# support post, put, patch only
|
25
|
+
return true unless request.post? || request.put? || request.patch?
|
26
|
+
return true if @operation_object.valid_request_content_type?(content_type)
|
23
27
|
|
24
|
-
|
28
|
+
raise Committee::InvalidRequest, %{"Content-Type" request header must be set to "#{@operation_object}".}
|
29
|
+
end
|
30
|
+
end
|
25
31
|
end
|
26
32
|
end
|
27
33
|
end
|
@@ -1,24 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Committee
|
2
|
-
|
3
|
-
|
4
|
+
module SchemaValidator
|
5
|
+
class OpenAPI3
|
6
|
+
class ResponseValidator
|
7
|
+
attr_reader :validate_success_only
|
4
8
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
# @param [Committee::SchemaValidator::Options] validator_option
|
10
|
+
# @param [Committee::SchemaValidator::OpenAPI3::OperationWrapper] operation_wrapper
|
11
|
+
def initialize(operation_wrapper, validator_option)
|
12
|
+
@operation_wrapper = operation_wrapper
|
13
|
+
@validate_success_only = validator_option.validate_success_only
|
14
|
+
@check_header = validator_option.check_header
|
15
|
+
end
|
12
16
|
|
13
|
-
|
14
|
-
|
17
|
+
def call(status, headers, response_data, strict)
|
18
|
+
return unless Committee::Middleware::ResponseValidation.validate?(status, validate_success_only)
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
20
|
+
#content_type = headers['Content-Type'].to_s.split(";").first.to_s
|
21
|
+
operation_wrapper.validate_response_params(status, headers, response_data, strict, check_header)
|
22
|
+
end
|
19
23
|
|
20
|
-
|
24
|
+
private
|
21
25
|
|
22
|
-
|
26
|
+
attr_reader :operation_wrapper, :check_header
|
27
|
+
end
|
28
|
+
end
|
23
29
|
end
|
24
30
|
end
|
@@ -1,37 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Committee
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
module SchemaValidator
|
5
|
+
class OpenAPI3
|
6
|
+
class Router
|
7
|
+
# @param [Committee::SchemaValidator::Option] validator_option
|
8
|
+
def initialize(schema, validator_option)
|
9
|
+
@schema = schema
|
10
|
+
@prefix_regexp = ::Committee::SchemaValidator.build_prefix_regexp(validator_option.prefix)
|
11
|
+
@validator_option = validator_option
|
12
|
+
end
|
9
13
|
|
10
|
-
|
11
|
-
|
14
|
+
def includes_request?(request)
|
15
|
+
return true unless @prefix_regexp
|
12
16
|
|
13
|
-
|
14
|
-
|
17
|
+
prefix_request?(request)
|
18
|
+
end
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
20
|
+
def build_schema_validator(request)
|
21
|
+
Committee::SchemaValidator::OpenAPI3.new(self, request, @validator_option)
|
22
|
+
end
|
19
23
|
|
20
|
-
|
21
|
-
|
22
|
-
|
24
|
+
def operation_object(request)
|
25
|
+
path = request.path
|
26
|
+
path = path.gsub(@prefix_regexp, '') if prefix_request?(request)
|
23
27
|
|
24
|
-
|
28
|
+
request_method = request.request_method.downcase
|
25
29
|
|
26
|
-
|
27
|
-
|
30
|
+
@schema.operation_object(path, request_method)
|
31
|
+
end
|
28
32
|
|
29
|
-
|
33
|
+
private
|
30
34
|
|
31
|
-
|
32
|
-
|
35
|
+
def prefix_request?(request)
|
36
|
+
return false unless @prefix_regexp
|
33
37
|
|
34
|
-
|
38
|
+
request.path =~ @prefix_regexp
|
39
|
+
end
|
40
|
+
end
|
35
41
|
end
|
36
42
|
end
|
37
43
|
end
|
@@ -1,45 +1,49 @@
|
|
1
|
-
|
2
|
-
class Option
|
3
|
-
# Boolean Options
|
4
|
-
attr_reader :allow_form_params,
|
5
|
-
:allow_get_body,
|
6
|
-
:allow_query_params,
|
7
|
-
:check_content_type,
|
8
|
-
:check_header,
|
9
|
-
:coerce_date_times,
|
10
|
-
:coerce_form_params,
|
11
|
-
:coerce_path_params,
|
12
|
-
:coerce_query_params,
|
13
|
-
:coerce_recursive,
|
14
|
-
:optimistic_json,
|
15
|
-
:validate_success_only
|
1
|
+
# frozen_string_literal: true
|
16
2
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
3
|
+
module Committee
|
4
|
+
module SchemaValidator
|
5
|
+
class Option
|
6
|
+
# Boolean Options
|
7
|
+
attr_reader :allow_form_params,
|
8
|
+
:allow_get_body,
|
9
|
+
:allow_query_params,
|
10
|
+
:check_content_type,
|
11
|
+
:check_header,
|
12
|
+
:coerce_date_times,
|
13
|
+
:coerce_form_params,
|
14
|
+
:coerce_path_params,
|
15
|
+
:coerce_query_params,
|
16
|
+
:coerce_recursive,
|
17
|
+
:optimistic_json,
|
18
|
+
:validate_success_only
|
21
19
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
@prefix = options[:prefix]
|
20
|
+
# Non-boolean options:
|
21
|
+
attr_reader :headers_key,
|
22
|
+
:params_key,
|
23
|
+
:prefix
|
27
24
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
@coerce_recursive = options.fetch(:coerce_recursive, true)
|
34
|
-
@optimistic_json = options.fetch(:optimistic_json, false)
|
25
|
+
def initialize(options, schema, schema_type)
|
26
|
+
# Non-boolean options
|
27
|
+
@headers_key = options[:headers_key] || "committee.headers"
|
28
|
+
@params_key = options[:params_key] || "committee.params"
|
29
|
+
@prefix = options[:prefix]
|
35
30
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
31
|
+
# Boolean options and have a common value by default
|
32
|
+
@allow_form_params = options.fetch(:allow_form_params, true)
|
33
|
+
@allow_query_params = options.fetch(:allow_query_params, true)
|
34
|
+
@check_content_type = options.fetch(:check_content_type, true)
|
35
|
+
@check_header = options.fetch(:check_header, true)
|
36
|
+
@coerce_recursive = options.fetch(:coerce_recursive, true)
|
37
|
+
@optimistic_json = options.fetch(:optimistic_json, false)
|
38
|
+
|
39
|
+
# Boolean options and have a different value by default
|
40
|
+
@allow_get_body = options.fetch(:allow_get_body, schema.driver.default_allow_get_body)
|
41
|
+
@coerce_date_times = options.fetch(:coerce_date_times, schema.driver.default_coerce_date_times)
|
42
|
+
@coerce_form_params = options.fetch(:coerce_form_params, schema.driver.default_coerce_form_params)
|
43
|
+
@coerce_path_params = options.fetch(:coerce_path_params, schema.driver.default_path_params)
|
44
|
+
@coerce_query_params = options.fetch(:coerce_query_params, schema.driver.default_query_params)
|
45
|
+
@validate_success_only = options.fetch(:validate_success_only, schema.driver.default_validate_success_only)
|
46
|
+
end
|
43
47
|
end
|
44
48
|
end
|
45
49
|
end
|
@@ -1,69 +1,73 @@
|
|
1
|
-
|
2
|
-
module Methods
|
3
|
-
def assert_schema_conform
|
4
|
-
assert_request_schema_confirm unless old_behavior
|
5
|
-
assert_response_schema_confirm
|
6
|
-
end
|
1
|
+
# frozen_string_literal: true
|
7
2
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
3
|
+
module Committee
|
4
|
+
module Test
|
5
|
+
module Methods
|
6
|
+
def assert_schema_conform
|
7
|
+
assert_request_schema_confirm unless old_behavior
|
8
|
+
assert_response_schema_confirm
|
12
9
|
end
|
13
10
|
|
14
|
-
|
15
|
-
|
11
|
+
def assert_request_schema_confirm
|
12
|
+
unless schema_validator.link_exist?
|
13
|
+
request = "`#{request_object.request_method} #{request_object.path_info}` undefined in schema."
|
14
|
+
raise Committee::InvalidRequest.new(request)
|
15
|
+
end
|
16
16
|
|
17
|
-
|
18
|
-
unless schema_validator.link_exist?
|
19
|
-
response = "`#{request_object.request_method} #{request_object.path_info}` undefined in schema."
|
20
|
-
raise Committee::InvalidResponse.new(response)
|
17
|
+
schema_validator.request_validate(request_object)
|
21
18
|
end
|
22
19
|
|
23
|
-
|
24
|
-
|
25
|
-
|
20
|
+
def assert_response_schema_confirm
|
21
|
+
unless schema_validator.link_exist?
|
22
|
+
response = "`#{request_object.request_method} #{request_object.path_info}` undefined in schema."
|
23
|
+
raise Committee::InvalidResponse.new(response)
|
24
|
+
end
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
status, headers, body = response_data
|
27
|
+
schema_validator.response_validate(status, headers, [body], true) if validate_response?(status)
|
28
|
+
end
|
30
29
|
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
def committee_options
|
31
|
+
raise "please set options"
|
32
|
+
end
|
34
33
|
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
def request_object
|
35
|
+
raise "please set object like 'last_request'"
|
36
|
+
end
|
38
37
|
|
39
|
-
|
40
|
-
|
41
|
-
|
38
|
+
def response_data
|
39
|
+
raise "please set response data like 'last_response.status, last_response.headers, last_response.body'"
|
40
|
+
end
|
42
41
|
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
def validate_response?(status)
|
43
|
+
Committee::Middleware::ResponseValidation.validate?(status, committee_options.fetch(:validate_success_only, false))
|
44
|
+
end
|
46
45
|
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
def schema
|
47
|
+
@schema ||= Committee::Middleware::Base.get_schema(committee_options)
|
48
|
+
end
|
50
49
|
|
51
|
-
|
52
|
-
|
53
|
-
|
50
|
+
def router
|
51
|
+
@router ||= schema.build_router(committee_options)
|
52
|
+
end
|
53
|
+
|
54
|
+
def schema_validator
|
55
|
+
@schema_validator ||= router.build_schema_validator(request_object)
|
56
|
+
end
|
54
57
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
58
|
+
def old_behavior
|
59
|
+
old_assert_behavior = committee_options.fetch(:old_assert_behavior, nil)
|
60
|
+
if old_assert_behavior.nil?
|
61
|
+
warn <<-MSG
|
62
|
+
[DEPRECATION] now assert_schema_conform check response schema only.
|
63
|
+
but we will change check request and response in future major version.
|
64
|
+
so if you want to conform response only, please use assert_response_schema_confirm,
|
65
|
+
or you can suppress this message and keep old behavior by setting old_assert_behavior=true.
|
66
|
+
MSG
|
67
|
+
old_assert_behavior = true
|
68
|
+
end
|
69
|
+
old_assert_behavior
|
65
70
|
end
|
66
|
-
old_assert_behavior
|
67
71
|
end
|
68
72
|
end
|
69
73
|
end
|
data/test/bin_test.rb
CHANGED
data/test/committee_test.rb
CHANGED
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_helper"
|
4
|
+
|
5
|
+
describe Committee::Drivers::HyperSchema::Driver do
|
6
|
+
before do
|
7
|
+
@driver = Committee::Drivers::HyperSchema::Driver.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "has a name" do
|
11
|
+
assert_equal :hyper_schema, @driver.name
|
12
|
+
end
|
13
|
+
|
14
|
+
it "has a schema class" do
|
15
|
+
assert_equal Committee::Drivers::HyperSchema::Schema, @driver.schema_class
|
16
|
+
end
|
17
|
+
|
18
|
+
it "parses a hyper-schema and builds routes" do
|
19
|
+
schema = @driver.parse(hyper_schema_data)
|
20
|
+
assert_kind_of Committee::Drivers::HyperSchema::Schema, schema
|
21
|
+
assert_equal @driver, schema.driver
|
22
|
+
|
23
|
+
assert_kind_of Hash, schema.routes
|
24
|
+
refute schema.routes.empty?
|
25
|
+
assert(schema.routes.keys.all? { |m|
|
26
|
+
["DELETE", "GET", "PATCH", "POST", "PUT"].include?(m)
|
27
|
+
})
|
28
|
+
|
29
|
+
schema.routes.each do |(_, method_routes)|
|
30
|
+
method_routes.each do |regex, link|
|
31
|
+
assert_kind_of Regexp, regex
|
32
|
+
assert_kind_of Committee::Drivers::HyperSchema::Link, link
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it "defaults to not coercing form parameters" do
|
38
|
+
assert_equal false, @driver.default_coerce_form_params
|
39
|
+
end
|
40
|
+
|
41
|
+
it "defaults to no path parameters" do
|
42
|
+
assert_equal false, @driver.default_path_params
|
43
|
+
end
|
44
|
+
|
45
|
+
it "defaults to no query parameters" do
|
46
|
+
assert_equal false, @driver.default_query_params
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|