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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/bin/committee-stub +1 -0
  3. data/lib/committee.rb +12 -34
  4. data/lib/committee/bin/committee_stub.rb +6 -4
  5. data/lib/committee/drivers.rb +15 -67
  6. data/lib/committee/drivers/driver.rb +47 -0
  7. data/lib/committee/drivers/hyper_schema.rb +8 -171
  8. data/lib/committee/drivers/hyper_schema/driver.rb +105 -0
  9. data/lib/committee/drivers/hyper_schema/link.rb +68 -0
  10. data/lib/committee/drivers/hyper_schema/schema.rb +22 -0
  11. data/lib/committee/drivers/open_api_2.rb +9 -416
  12. data/lib/committee/drivers/open_api_2/driver.rb +253 -0
  13. data/lib/committee/drivers/open_api_2/header_schema_builder.rb +33 -0
  14. data/lib/committee/drivers/open_api_2/link.rb +36 -0
  15. data/lib/committee/drivers/open_api_2/parameter_schema_builder.rb +83 -0
  16. data/lib/committee/drivers/open_api_2/schema.rb +26 -0
  17. data/lib/committee/drivers/open_api_2/schema_builder.rb +33 -0
  18. data/lib/committee/drivers/open_api_3.rb +7 -75
  19. data/lib/committee/drivers/open_api_3/driver.rb +51 -0
  20. data/lib/committee/drivers/open_api_3/schema.rb +41 -0
  21. data/lib/committee/drivers/schema.rb +23 -0
  22. data/lib/committee/errors.rb +2 -0
  23. data/lib/committee/middleware.rb +11 -0
  24. data/lib/committee/middleware/base.rb +38 -34
  25. data/lib/committee/middleware/request_validation.rb +51 -30
  26. data/lib/committee/middleware/response_validation.rb +49 -26
  27. data/lib/committee/middleware/stub.rb +55 -51
  28. data/lib/committee/request_unpacker.rb +3 -1
  29. data/lib/committee/schema_validator.rb +23 -0
  30. data/lib/committee/schema_validator/hyper_schema.rb +85 -74
  31. data/lib/committee/schema_validator/hyper_schema/parameter_coercer.rb +60 -54
  32. data/lib/committee/schema_validator/hyper_schema/request_validator.rb +43 -37
  33. data/lib/committee/schema_validator/hyper_schema/response_generator.rb +86 -80
  34. data/lib/committee/schema_validator/hyper_schema/response_validator.rb +65 -59
  35. data/lib/committee/schema_validator/hyper_schema/router.rb +35 -29
  36. data/lib/committee/schema_validator/hyper_schema/string_params_coercer.rb +87 -81
  37. data/lib/committee/schema_validator/open_api_3.rb +71 -61
  38. data/lib/committee/schema_validator/open_api_3/operation_wrapper.rb +121 -115
  39. data/lib/committee/schema_validator/open_api_3/request_validator.rb +24 -18
  40. data/lib/committee/schema_validator/open_api_3/response_validator.rb +22 -16
  41. data/lib/committee/schema_validator/open_api_3/router.rb +30 -24
  42. data/lib/committee/schema_validator/option.rb +42 -38
  43. data/lib/committee/test/methods.rb +55 -51
  44. data/lib/committee/validation_error.rb +2 -0
  45. data/test/bin/committee_stub_test.rb +3 -1
  46. data/test/bin_test.rb +3 -1
  47. data/test/committee_test.rb +3 -1
  48. data/test/drivers/hyper_schema/driver_test.rb +49 -0
  49. data/test/drivers/{hyper_schema_test.rb → hyper_schema/link_test.rb} +2 -45
  50. data/test/drivers/open_api_2/driver_test.rb +156 -0
  51. data/test/drivers/open_api_2/header_schema_builder_test.rb +26 -0
  52. data/test/drivers/open_api_2/link_test.rb +52 -0
  53. data/test/drivers/open_api_2/parameter_schema_builder_test.rb +195 -0
  54. data/test/drivers/{open_api_3_test.rb → open_api_3/driver_test.rb} +5 -3
  55. data/test/drivers_test.rb +12 -10
  56. data/test/middleware/base_test.rb +3 -1
  57. data/test/middleware/request_validation_open_api_3_test.rb +4 -2
  58. data/test/middleware/request_validation_test.rb +46 -5
  59. data/test/middleware/response_validation_open_api_3_test.rb +3 -1
  60. data/test/middleware/response_validation_test.rb +39 -4
  61. data/test/middleware/stub_test.rb +3 -1
  62. data/test/request_unpacker_test.rb +2 -2
  63. data/test/schema_validator/hyper_schema/parameter_coercer_test.rb +2 -2
  64. data/test/schema_validator/hyper_schema/request_validator_test.rb +3 -1
  65. data/test/schema_validator/hyper_schema/response_generator_test.rb +3 -1
  66. data/test/schema_validator/hyper_schema/response_validator_test.rb +3 -1
  67. data/test/schema_validator/hyper_schema/router_test.rb +5 -3
  68. data/test/schema_validator/hyper_schema/string_params_coercer_test.rb +3 -1
  69. data/test/schema_validator/open_api_3/operation_wrapper_test.rb +3 -1
  70. data/test/schema_validator/open_api_3/request_validator_test.rb +11 -1
  71. data/test/schema_validator/open_api_3/response_validator_test.rb +3 -1
  72. data/test/test/methods_new_version_test.rb +3 -1
  73. data/test/test/methods_test.rb +4 -2
  74. data/test/test_helper.rb +16 -16
  75. data/test/validation_error_test.rb +3 -1
  76. metadata +52 -6
  77. data/lib/committee/schema_validator/schema_validator.rb +0 -15
  78. data/test/drivers/open_api_2_test.rb +0 -416
@@ -1,79 +1,11 @@
1
- module Committee::Drivers
2
- class OpenAPI3 < Committee::Drivers::Driver
3
- def default_coerce_date_times
4
- true
5
- end
6
-
7
- # Whether parameters that were form-encoded will be coerced by default.
8
- def default_coerce_form_params
9
- true
10
- end
11
-
12
- def default_allow_get_body
13
- false
14
- end
15
-
16
- # Whether parameters in a request's path will be considered and coerced by
17
- # default.
18
- def default_path_params
19
- true
20
- end
21
-
22
- # Whether parameters in a request's query string will be considered and
23
- # coerced by default.
24
- def default_query_params
25
- true
26
- end
27
-
28
- def default_validate_success_only
29
- false
30
- end
31
-
32
- def name
33
- :open_api_3
34
- end
1
+ # frozen_string_literal: true
35
2
 
36
- # @return [Committee::Drivers::OpenAPI3::Schema]
37
- def parse(open_api)
38
- schema_class.new(self, open_api)
39
- end
40
-
41
- def schema_class
42
- Committee::Drivers::OpenAPI3::Schema
43
- end
44
-
45
- class Schema < Committee::Drivers::Schema
46
- attr_reader :open_api
47
- attr_reader :validator_option
48
-
49
- # @!attribute [r] open_api
50
- # @return [OpenAPIParser::Schemas::OpenAPI]
51
-
52
- def initialize(driver, open_api)
53
- @open_api = open_api
54
- @driver = driver
55
- end
56
-
57
- def supports_stub?
58
- false
59
- end
60
-
61
- def driver # we don't use attr_reader because this method override super class
62
- @driver
63
- end
64
-
65
- def build_router(options)
66
- @validator_option = Committee::SchemaValidator::Option.new(options, self, :open_api_3)
67
- Committee::SchemaValidator::OpenAPI3::Router.new(self, @validator_option)
68
- end
69
-
70
- # OpenAPI3 only
71
- def operation_object(path, method)
72
- request_operation = open_api.request_operation(method, path)
73
- return nil unless request_operation
74
-
75
- Committee::SchemaValidator::OpenAPI3::OperationWrapper.new(request_operation)
76
- end
3
+ module Committee
4
+ module Drivers
5
+ module OpenAPI3
77
6
  end
78
7
  end
79
8
  end
9
+
10
+ require_relative 'open_api_3/driver'
11
+ require_relative 'open_api_3/schema'
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Committee
4
+ module Drivers
5
+ module OpenAPI3
6
+ class Driver < ::Committee::Drivers::Driver
7
+ def default_coerce_date_times
8
+ true
9
+ end
10
+
11
+ # Whether parameters that were form-encoded will be coerced by default.
12
+ def default_coerce_form_params
13
+ true
14
+ end
15
+
16
+ def default_allow_get_body
17
+ false
18
+ end
19
+
20
+ # Whether parameters in a request's path will be considered and coerced by
21
+ # default.
22
+ def default_path_params
23
+ true
24
+ end
25
+
26
+ # Whether parameters in a request's query string will be considered and
27
+ # coerced by default.
28
+ def default_query_params
29
+ true
30
+ end
31
+
32
+ def default_validate_success_only
33
+ false
34
+ end
35
+
36
+ def name
37
+ :open_api_3
38
+ end
39
+
40
+ # @return [Committee::Drivers::OpenAPI3::Schema]
41
+ def parse(open_api)
42
+ schema_class.new(self, open_api)
43
+ end
44
+
45
+ def schema_class
46
+ Committee::Drivers::OpenAPI3::Schema
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Committee
4
+ module Drivers
5
+ module OpenAPI3
6
+ class Schema < ::Committee::Drivers::Schema
7
+ attr_reader :open_api
8
+ attr_reader :validator_option
9
+
10
+ # @!attribute [r] open_api
11
+ # @return [OpenAPIParser::Schemas::OpenAPI]
12
+
13
+ def initialize(driver, open_api)
14
+ @open_api = open_api
15
+ @driver = driver
16
+ end
17
+
18
+ def supports_stub?
19
+ false
20
+ end
21
+
22
+ def driver # we don't use attr_reader because this method override super class
23
+ @driver
24
+ end
25
+
26
+ def build_router(options)
27
+ @validator_option = Committee::SchemaValidator::Option.new(options, self, :open_api_3)
28
+ Committee::SchemaValidator::OpenAPI3::Router.new(self, @validator_option)
29
+ end
30
+
31
+ # OpenAPI3 only
32
+ def operation_object(path, method)
33
+ request_operation = open_api.request_operation(method, path)
34
+ return nil unless request_operation
35
+
36
+ Committee::SchemaValidator::OpenAPI3::OperationWrapper.new(request_operation)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Committee
4
+ module Drivers
5
+ # Schema is a base class for driver schema implementations.
6
+ class Schema
7
+ # A link back to the derivative instance of Committee::Drivers::Driver
8
+ # that create this schema.
9
+ def driver
10
+ raise "needs implementation"
11
+ end
12
+
13
+ def build_router(options)
14
+ raise "needs implementation"
15
+ end
16
+
17
+ # Stubs are supported in JSON Hyper-Schema and OpenAPI 2, but not yet in OpenAPI 3
18
+ def supports_stub?
19
+ true
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Committee
2
4
  class Error < StandardError
3
5
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Committee
4
+ module Middleware
5
+ end
6
+ end
7
+
8
+ require_relative "middleware/base"
9
+ require_relative "middleware/request_validation"
10
+ require_relative "middleware/response_validation"
11
+ require_relative "middleware/stub"
@@ -1,50 +1,54 @@
1
- module Committee::Middleware
2
- class Base
3
- def initialize(app, options={})
4
- @app = app
1
+ # frozen_string_literal: true
5
2
 
6
- @error_class = options.fetch(:error_class, Committee::ValidationError)
7
- @error_handler = options[:error_handler]
3
+ module Committee
4
+ module Middleware
5
+ class Base
6
+ def initialize(app, options={})
7
+ @app = app
8
8
 
9
- @raise = options[:raise]
10
- @schema = self.class.get_schema(options)
9
+ @error_class = options.fetch(:error_class, Committee::ValidationError)
10
+ @error_handler = options[:error_handler]
11
11
 
12
- @router = @schema.build_router(options)
13
- end
14
-
15
- def call(env)
16
- request = Rack::Request.new(env)
12
+ @raise = options[:raise]
13
+ @schema = self.class.get_schema(options)
17
14
 
18
- if @router.includes_request?(request)
19
- handle(request)
20
- else
21
- @app.call(request.env)
15
+ @router = @schema.build_router(options)
22
16
  end
23
- end
24
17
 
25
- class << self
26
- def get_schema(options)
27
- schema = options[:schema]
28
- unless schema
29
- schema = Committee::Drivers::load_from_file(options[:schema_path]) if options[:schema_path]
18
+ def call(env)
19
+ request = Rack::Request.new(env)
30
20
 
31
- raise(ArgumentError, "Committee: need option `schema` or `schema_path`") unless schema
21
+ if @router.includes_request?(request)
22
+ handle(request)
23
+ else
24
+ @app.call(request.env)
32
25
  end
26
+ end
33
27
 
34
- # Expect the type we want by now. If we don't have it, the user passed
35
- # something else non-standard in.
36
- if !schema.is_a?(Committee::Drivers::Schema)
37
- raise ArgumentError, "Committee: schema expected to be an instance of Committee::Drivers::Schema."
38
- end
28
+ class << self
29
+ def get_schema(options)
30
+ schema = options[:schema]
31
+ unless schema
32
+ schema = Committee::Drivers::load_from_file(options[:schema_path]) if options[:schema_path]
39
33
 
40
- return schema
34
+ raise(ArgumentError, "Committee: need option `schema` or `schema_path`") unless schema
35
+ end
36
+
37
+ # Expect the type we want by now. If we don't have it, the user passed
38
+ # something else non-standard in.
39
+ if !schema.is_a?(Committee::Drivers::Schema)
40
+ raise ArgumentError, "Committee: schema expected to be an instance of Committee::Drivers::Schema."
41
+ end
42
+
43
+ return schema
44
+ end
41
45
  end
42
- end
43
46
 
44
- private
47
+ private
45
48
 
46
- def build_schema_validator(request)
47
- @router.build_schema_validator(request)
49
+ def build_schema_validator(request)
50
+ @router.build_schema_validator(request)
51
+ end
48
52
  end
49
53
  end
50
54
  end
@@ -1,36 +1,57 @@
1
- module Committee::Middleware
2
- class RequestValidation < Base
3
- def initialize(app, options={})
4
- super
1
+ # frozen_string_literal: true
5
2
 
6
- @strict = options[:strict]
3
+ module Committee
4
+ module Middleware
5
+ class RequestValidation < Base
6
+ def initialize(app, options={})
7
+ super
7
8
 
8
- # deprecated
9
- @allow_extra = options[:allow_extra]
10
- end
9
+ @strict = options[:strict]
10
+
11
+ # deprecated
12
+ @allow_extra = options[:allow_extra]
13
+ end
14
+
15
+ def handle(request)
16
+ schema_validator = build_schema_validator(request)
17
+ schema_validator.request_validate(request)
18
+
19
+ raise Committee::NotFound, "That request method and path combination isn't defined." if !schema_validator.link_exist? && @strict
20
+
21
+ @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
+ end
38
+
39
+ private
40
+
41
+ def handle_exception(e, env)
42
+ return unless @error_handler
43
+
44
+ if @error_handler.arity > 1
45
+ @error_handler.call(e, env)
46
+ else
47
+ warn <<-MESSAGE
48
+ [DEPRECATION] Using `error_handler.call(exception)` is deprecated and will be change to
49
+ `error_handler.call(exception, request.env)` in next major version.
50
+ MESSAGE
11
51
 
12
- def handle(request)
13
- schema_validator = build_schema_validator(request)
14
- schema_validator.request_validate(request)
15
-
16
- raise Committee::NotFound, "That request method and path combination isn't defined." if !schema_validator.link_exist? && @strict
17
-
18
- @app.call(request.env)
19
- rescue Committee::BadRequest, Committee::InvalidRequest
20
- @error_handler.call($!) if @error_handler
21
- raise if @raise
22
- @error_class.new(400, :bad_request, $!.message).render
23
- rescue Committee::NotFound => e
24
- raise if @raise
25
- @error_class.new(
26
- 404,
27
- :not_found,
28
- e.message
29
- ).render
30
- rescue JSON::ParserError
31
- @error_handler.call($!) if @error_handler
32
- raise Committee::InvalidRequest if @raise
33
- @error_class.new(400, :bad_request, "Request body wasn't valid JSON.").render
52
+ @error_handler.call(e)
53
+ end
54
+ end
34
55
  end
35
56
  end
36
57
  end
@@ -1,32 +1,55 @@
1
- module Committee::Middleware
2
- class ResponseValidation < Base
3
- attr_reader :validate_success_only
1
+ # frozen_string_literal: true
4
2
 
5
- def initialize(app, options = {})
6
- super
7
- @validate_success_only = @schema.validator_option.validate_success_only
8
- end
3
+ module Committee
4
+ module Middleware
5
+ class ResponseValidation < Base
6
+ attr_reader :validate_success_only
9
7
 
10
- def handle(request)
11
- status, headers, response = @app.call(request.env)
12
-
13
- v = build_schema_validator(request)
14
- v.response_validate(status, headers, response) if v.link_exist? && self.class.validate?(status, validate_success_only)
15
-
16
- [status, headers, response]
17
- rescue Committee::InvalidResponse
18
- @error_handler.call($!) if @error_handler
19
- raise if @raise
20
- @error_class.new(500, :invalid_response, $!.message).render
21
- rescue JSON::ParserError
22
- @error_handler.call($!) if @error_handler
23
- raise Committee::InvalidResponse if @raise
24
- @error_class.new(500, :invalid_response, "Response wasn't valid JSON.").render
25
- end
8
+ def initialize(app, options = {})
9
+ super
10
+ @validate_success_only = @schema.validator_option.validate_success_only
11
+ end
12
+
13
+ def handle(request)
14
+ status, headers, response = @app.call(request.env)
15
+
16
+ v = build_schema_validator(request)
17
+ v.response_validate(status, headers, response) if v.link_exist? && self.class.validate?(status, validate_success_only)
18
+
19
+ [status, headers, response]
20
+ rescue Committee::InvalidResponse
21
+ handle_exception($!, request.env)
22
+
23
+ raise if @raise
24
+ @error_class.new(500, :invalid_response, $!.message).render
25
+ rescue JSON::ParserError
26
+ handle_exception($!, request.env)
27
+
28
+ raise Committee::InvalidResponse if @raise
29
+ @error_class.new(500, :invalid_response, "Response wasn't valid JSON.").render
30
+ end
31
+
32
+ class << self
33
+ def validate?(status, validate_success_only)
34
+ status != 204 && (!validate_success_only || (200...300).include?(status))
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def handle_exception(e, env)
41
+ return unless @error_handler
42
+
43
+ if @error_handler.arity > 1
44
+ @error_handler.call(e, env)
45
+ else
46
+ warn <<-MESSAGE
47
+ [DEPRECATION] Using `error_handler.call(exception)` is deprecated and will be change to
48
+ `error_handler.call(exception, request.env)` in next major version.
49
+ MESSAGE
26
50
 
27
- class << self
28
- def validate?(status, validate_success_only)
29
- status != 204 && (!validate_success_only || (200...300).include?(status))
51
+ @error_handler.call(e)
52
+ end
30
53
  end
31
54
  end
32
55
  end