committee 3.1.0 → 3.1.1
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/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
|
+
|