committee 4.1.0 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9bef22bebc103d1bee78ba294078cd56e34e37da3e92b5cb89aba683a2361c74
4
- data.tar.gz: 76f012e3f28bd5275af941a372563f00b3bf68e1c0332d0e78affc18cbac9f2e
3
+ metadata.gz: 108842305271b038db8a6a49bd4ec9da83ea573a5061144484f4704a4af278df
4
+ data.tar.gz: 216360635fabf23f082f768594c4799ef4c71f3de4cf7ff7ffc4ac2b7fc5a72c
5
5
  SHA512:
6
- metadata.gz: da601220eca1ea05bb829a61a65bf6928262be27c73647de756f44b07329752efe6818be1a79b95bb51ad2e00025d08ff5fbb5410acfdc670d43f6816c6614f1
7
- data.tar.gz: c0fad32bef922020708c194065d0de90fccc9d33d00354b4c8a4f3208e18b4720030e01810e798107894e6f503e8145fef11fd12afa1ba1f0b5b017f3b58eeda
6
+ metadata.gz: 417368733fb254f0211dd9ff6b273bf722db984325326816e3568ba7352da4079fb27c1405029d7191ae17e232d357041474f89ce6b7209c063911e8f4db26b3
7
+ data.tar.gz: '05682d9aaf2688ef511484bdaca307c1ff63dcefbdf1e4b6dcece592db7a548c5fa7ee0bb3498f4f1b903e20f9944a58790c335fc7c69251bdf0c65e33e3b19c'
data/lib/committee.rb CHANGED
@@ -16,12 +16,11 @@ module Committee
16
16
  end
17
17
 
18
18
  def self.warn_deprecated(message)
19
- if !$VERBOSE.nil?
20
- $stderr.puts(message)
21
- end
19
+ warn("[DEPRECATION] #{message}")
22
20
  end
23
21
  end
24
22
 
23
+ require_relative "committee/utils"
25
24
  require_relative "committee/drivers"
26
25
  require_relative "committee/errors"
27
26
  require_relative "committee/middleware"
@@ -31,3 +30,4 @@ require_relative "committee/validation_error"
31
30
 
32
31
  require_relative "committee/bin/committee_stub"
33
32
  require_relative "committee/test/methods"
33
+ require_relative "committee/test/schema_coverage"
@@ -156,7 +156,6 @@ module Committee
156
156
 
157
157
  methods.each do |method, link_data|
158
158
  method = method.upcase
159
-
160
159
  link = Link.new
161
160
  link.enc_type = schema.consumes
162
161
  link.href = href
@@ -8,9 +8,21 @@ module Committee
8
8
  end
9
9
 
10
10
  class InvalidRequest < Error
11
+ attr_reader :original_error
12
+
13
+ def initialize(error_message=nil, original_error: nil)
14
+ @original_error = original_error
15
+ super(error_message)
16
+ end
11
17
  end
12
18
 
13
19
  class InvalidResponse < Error
20
+ attr_reader :original_error
21
+
22
+ def initialize(error_message=nil, original_error: nil)
23
+ @original_error = original_error
24
+ super(error_message)
25
+ end
14
26
  end
15
27
 
16
28
  class NotFound < Error
@@ -7,9 +7,6 @@ module Committee
7
7
  super
8
8
 
9
9
  @strict = options[:strict]
10
-
11
- # deprecated
12
- @allow_extra = options[:allow_extra]
13
10
  end
14
11
 
15
12
  def handle(request)
@@ -21,14 +18,14 @@ module Committee
21
18
  rescue Committee::BadRequest, Committee::InvalidRequest
22
19
  handle_exception($!, request.env)
23
20
  raise if @raise
24
- return @error_class.new(400, :bad_request, $!.message).render unless @ignore_error
21
+ return @error_class.new(400, :bad_request, $!.message, request).render unless @ignore_error
25
22
  rescue Committee::NotFound => e
26
23
  raise if @raise
27
- return @error_class.new(404, :not_found, e.message).render unless @ignore_error
24
+ return @error_class.new(404, :not_found, e.message, request).render unless @ignore_error
28
25
  rescue JSON::ParserError
29
26
  handle_exception($!, request.env)
30
27
  raise Committee::InvalidRequest if @raise
31
- return @error_class.new(400, :bad_request, "Request body wasn't valid JSON.").render unless @ignore_error
28
+ return @error_class.new(400, :bad_request, "Request body wasn't valid JSON.", request).render unless @ignore_error
32
29
  end
33
30
 
34
31
  @app.call(request.env)
@@ -42,11 +39,7 @@ module Committee
42
39
  if @error_handler.arity > 1
43
40
  @error_handler.call(e, env)
44
41
  else
45
- warn <<-MESSAGE
46
- [DEPRECATION] Using `error_handler.call(exception)` is deprecated and will be change to
47
- `error_handler.call(exception, request.env)` in next major version.
48
- MESSAGE
49
-
42
+ Committee.warn_deprecated('Using `error_handler.call(exception)` is deprecated and will be change to `error_handler.call(exception, request.env)` in next major version.')
50
43
  @error_handler.call(e)
51
44
  end
52
45
  end
@@ -7,13 +7,17 @@ module Committee
7
7
 
8
8
  def initialize(app, options = {})
9
9
  super
10
+
11
+ unless options[:strict].nil?
12
+ Committee.warn_deprecated("Committee: Committee::Middleware::ResponseValidation doesn't support strict option now but we'll support this option. This change break backward compatibility so please remove strict option from ResponseValidation")
13
+ end
10
14
  @validate_success_only = @schema.validator_option.validate_success_only
11
15
  end
12
16
 
13
17
  def handle(request)
14
- begin
15
- status, headers, response = @app.call(request.env)
18
+ status, headers, response = @app.call(request.env)
16
19
 
20
+ begin
17
21
  v = build_schema_validator(request)
18
22
  v.response_validate(status, headers, response) if v.link_exist? && self.class.validate?(status, validate_success_only)
19
23
 
@@ -46,11 +50,7 @@ module Committee
46
50
  if @error_handler.arity > 1
47
51
  @error_handler.call(e, env)
48
52
  else
49
- warn <<-MESSAGE
50
- [DEPRECATION] Using `error_handler.call(exception)` is deprecated and will be change to
51
- `error_handler.call(exception, request.env)` in next major version.
52
- MESSAGE
53
-
53
+ Committee.warn_deprecated('Using `error_handler.call(exception)` is deprecated and will be change to `error_handler.call(exception, request.env)` in next major version.')
54
54
  @error_handler.call(e)
55
55
  end
56
56
  end
@@ -2,84 +2,82 @@
2
2
 
3
3
  module Committee
4
4
  class RequestUnpacker
5
- def initialize(request, options={})
6
- @request = request
5
+ class << self
6
+ # Enable string or symbol key access to the nested params hash.
7
+ #
8
+ # (Copied from Sinatra)
9
+ def indifferent_params(object)
10
+ case object
11
+ when Hash
12
+ new_hash = Committee::Utils.indifferent_hash
13
+ object.each { |key, value| new_hash[key] = indifferent_params(value) }
14
+ new_hash
15
+ when Array
16
+ object.map { |item| indifferent_params(item) }
17
+ else
18
+ object
19
+ end
20
+ end
21
+ end
7
22
 
23
+ def initialize(options={})
8
24
  @allow_form_params = options[:allow_form_params]
9
25
  @allow_get_body = options[:allow_get_body]
10
26
  @allow_query_params = options[:allow_query_params]
11
- @coerce_form_params = options[:coerce_form_params]
12
27
  @optimistic_json = options[:optimistic_json]
13
- @schema_validator = options[:schema_validator]
14
28
  end
15
29
 
16
- def call
30
+ # reutrn params and is_form_params
31
+ def unpack_request_params(request)
17
32
  # if Content-Type is empty or JSON, and there was a request body, try to
18
33
  # interpret it as JSON
19
- params = if !@request.media_type || @request.media_type =~ %r{application/.*json}
20
- parse_json
34
+ params = if !request.media_type || request.media_type =~ %r{application/(?:.*\+)?json}
35
+ parse_json(request)
21
36
  elsif @optimistic_json
22
37
  begin
23
- parse_json
38
+ parse_json(request)
24
39
  rescue JSON::ParserError
25
40
  nil
26
41
  end
27
42
  end
28
43
 
29
- params = if params
30
- params
31
- elsif @allow_form_params && %w[application/x-www-form-urlencoded multipart/form-data].include?(@request.media_type)
44
+ return [params, false] if params
45
+
46
+ if @allow_form_params && %w[application/x-www-form-urlencoded multipart/form-data].include?(request.media_type)
32
47
  # Actually, POST means anything in the request body, could be from
33
48
  # PUT or PATCH too. Silly Rack.
34
- p = @request.POST
35
-
36
- @schema_validator.coerce_form_params(p) if @coerce_form_params
37
-
38
- p
39
- else
40
- {}
49
+ return [request.POST, true] if request.POST
41
50
  end
42
51
 
43
- if @allow_query_params
44
- [indifferent_params(@request.GET).merge(params), headers]
45
- else
46
- [params, headers]
47
- end
52
+ [{}, false]
48
53
  end
49
54
 
50
- private
51
-
52
- # Creates a Hash with indifferent access.
53
- #
54
- # (Copied from Sinatra)
55
- def indifferent_hash
56
- Hash.new { |hash,key| hash[key.to_s] if Symbol === key }
55
+ def unpack_query_params(request)
56
+ @allow_query_params ? self.class.indifferent_params(request.GET) : {}
57
57
  end
58
58
 
59
- # Enable string or symbol key access to the nested params hash.
60
- #
61
- # (Copied from Sinatra)
62
- def indifferent_params(object)
63
- case object
64
- when Hash
65
- new_hash = indifferent_hash
66
- object.each { |key, value| new_hash[key] = indifferent_params(value) }
67
- new_hash
68
- when Array
69
- object.map { |item| indifferent_params(item) }
70
- else
71
- object
59
+ def unpack_headers(request)
60
+ env = request.env
61
+ base = env.keys.grep(/HTTP_/).inject({}) do |headers, key|
62
+ headerized_key = key.gsub(/^HTTP_/, '').gsub(/_/, '-')
63
+ headers[headerized_key] = env[key]
64
+ headers
72
65
  end
66
+
67
+ base['Content-Type'] = env['CONTENT_TYPE'] if env['CONTENT_TYPE']
68
+ base
73
69
  end
74
70
 
75
- def parse_json
76
- return nil if @request.request_method == "GET" && !@allow_get_body
71
+ private
72
+
73
+ def parse_json(request)
74
+ return nil if request.request_method == "GET" && !@allow_get_body
77
75
 
78
- body = @request.body.read
76
+ body = request.body.read
79
77
  # if request body is empty, we just have empty params
80
78
  return nil if body.length == 0
81
79
 
82
- @request.body.rewind
80
+ request.body.rewind
83
81
  hash = JSON.parse(body)
84
82
  # We want a hash specifically. '42', 42, and [42] will all be
85
83
  # decoded properly, but we can't use them here.
@@ -87,19 +85,7 @@ module Committee
87
85
  raise BadRequest,
88
86
  "Invalid JSON input. Require object with parameters as keys."
89
87
  end
90
- indifferent_params(hash)
91
- end
92
-
93
- def headers
94
- env = @request.env
95
- base = env.keys.grep(/HTTP_/).inject({}) do |headers, key|
96
- headerized_key = key.gsub(/^HTTP_/, '').gsub(/_/, '-')
97
- headers[headerized_key] = env[key]
98
- headers
99
- end
100
-
101
- base['Content-Type'] = env['CONTENT_TYPE'] if env['CONTENT_TYPE']
102
- base
88
+ self.class.indifferent_params(hash)
103
89
  end
104
90
  end
105
91
  end
@@ -11,18 +11,8 @@ module Committee
11
11
  end
12
12
 
13
13
  def request_validate(request)
14
- # Attempts to coerce parameters that appear in a link's URL to Ruby
15
- # types that can be validated with a schema.
16
- param_matches_hash = validator_option.coerce_path_params ? coerce_path_params : {}
17
-
18
- # Attempts to coerce parameters that appear in a query string to Ruby
19
- # types that can be validated with a schema.
20
- coerce_query_params(request) if validator_option.coerce_query_params
21
-
22
14
  request_unpack(request)
23
15
 
24
- request.env[validator_option.params_key].merge!(param_matches_hash) if param_matches_hash
25
-
26
16
  request_schema_validation(request)
27
17
  parameter_coerce!(request, link, validator_option.params_key)
28
18
  parameter_coerce!(request, link, "rack.request.query_hash") if link_exist? && !request.GET.nil? && !link.schema.nil?
@@ -50,16 +40,10 @@ module Committee
50
40
  !link.nil?
51
41
  end
52
42
 
53
- def coerce_form_params(parameter)
54
- return unless link_exist?
55
- return unless link.schema
56
- Committee::SchemaValidator::HyperSchema::StringParamsCoercer.new(parameter, link.schema).call!
57
- end
58
-
59
43
  private
60
44
 
61
45
  def coerce_path_params
62
- return unless link_exist?
46
+ return {} unless link_exist?
63
47
 
64
48
  Committee::SchemaValidator::HyperSchema::StringParamsCoercer.new(param_matches, link.schema, coerce_recursive: validator_option.coerce_recursive).call!
65
49
  param_matches
@@ -73,15 +57,38 @@ module Committee
73
57
  end
74
58
 
75
59
  def request_unpack(request)
76
- request.env[validator_option.params_key], request.env[validator_option.headers_key] = Committee::RequestUnpacker.new(
77
- request,
78
- allow_form_params: validator_option.allow_form_params,
79
- allow_get_body: validator_option.allow_get_body,
80
- allow_query_params: validator_option.allow_query_params,
81
- coerce_form_params: validator_option.coerce_form_params,
82
- optimistic_json: validator_option.optimistic_json,
83
- schema_validator: self
84
- ).call
60
+ unpacker = Committee::RequestUnpacker.new(
61
+ allow_form_params: validator_option.allow_form_params,
62
+ allow_get_body: validator_option.allow_get_body,
63
+ allow_query_params: validator_option.allow_query_params,
64
+ optimistic_json: validator_option.optimistic_json,
65
+ )
66
+
67
+ request.env[validator_option.headers_key] = unpacker.unpack_headers(request)
68
+
69
+ # Attempts to coerce parameters that appear in a link's URL to Ruby
70
+ # types that can be validated with a schema.
71
+ param_matches_hash = validator_option.coerce_path_params ? coerce_path_params : {}
72
+
73
+ # Attempts to coerce parameters that appear in a query string to Ruby
74
+ # types that can be validated with a schema.
75
+ coerce_query_params(request) if validator_option.coerce_query_params
76
+
77
+ query_param = unpacker.unpack_query_params(request)
78
+ request_param, is_form_params = unpacker.unpack_request_params(request)
79
+ coerce_form_params(request_param) if validator_option.coerce_form_params && is_form_params
80
+ request.env[validator_option.request_body_hash_key] = request_param
81
+
82
+ request.env[validator_option.params_key] = Committee::Utils.indifferent_hash
83
+ request.env[validator_option.params_key].merge!(Committee::Utils.deep_copy(query_param))
84
+ request.env[validator_option.params_key].merge!(Committee::Utils.deep_copy(request_param))
85
+ request.env[validator_option.params_key].merge!(Committee::Utils.deep_copy(param_matches_hash))
86
+ end
87
+
88
+ def coerce_form_params(parameter)
89
+ return unless link_exist?
90
+ return unless link.schema
91
+ Committee::SchemaValidator::HyperSchema::StringParamsCoercer.new(parameter, link.schema).call!
85
92
  end
86
93
 
87
94
  def request_schema_validation(request)
@@ -14,12 +14,7 @@ module Committee
14
14
  def request_validate(request)
15
15
  return unless link_exist?
16
16
 
17
- path_params = validator_option.coerce_path_params ? coerce_path_params : {}
18
-
19
17
  request_unpack(request)
20
-
21
- request.env[validator_option.params_key]&.merge!(path_params) unless path_params.empty?
22
-
23
18
  request_schema_validation(request)
24
19
 
25
20
  copy_coerced_data_to_query_hash(request)
@@ -49,16 +44,13 @@ module Committee
49
44
  !@operation_object.nil?
50
45
  end
51
46
 
52
- def coerce_form_params(_parameter)
53
- # Empty because request_schema_validation checks and coerces
54
- end
55
-
56
47
  private
57
48
 
58
49
  attr_reader :validator_option
59
50
 
60
51
  def coerce_path_params
61
- @operation_object.coerce_path_parameter(@validator_option)
52
+ return Committee::Utils.indifferent_hash unless validator_option.coerce_path_params
53
+ Committee::RequestUnpacker.indifferent_params(@operation_object.coerce_path_parameter(@validator_option))
62
54
  end
63
55
 
64
56
  def request_schema_validation(request)
@@ -73,22 +65,36 @@ module Committee
73
65
  end
74
66
 
75
67
  def request_unpack(request)
76
- request.env[validator_option.params_key], request.env[validator_option.headers_key] = Committee::RequestUnpacker.new(
77
- request,
78
- allow_form_params: validator_option.allow_form_params,
79
- allow_get_body: validator_option.allow_get_body,
80
- allow_query_params: validator_option.allow_query_params,
81
- coerce_form_params: validator_option.coerce_form_params,
82
- optimistic_json: validator_option.optimistic_json,
83
- schema_validator: self
84
- ).call
68
+ unpacker = Committee::RequestUnpacker.new(
69
+ allow_form_params: validator_option.allow_form_params,
70
+ allow_get_body: validator_option.allow_get_body,
71
+ allow_query_params: validator_option.allow_query_params,
72
+ optimistic_json: validator_option.optimistic_json,
73
+ )
74
+
75
+ request.env[validator_option.headers_key] = unpacker.unpack_headers(request)
76
+
77
+ request_param, is_form_params = unpacker.unpack_request_params(request)
78
+ request.env[validator_option.request_body_hash_key] = request_param
79
+ request.env[validator_option.path_hash_key] = coerce_path_params
80
+
81
+ query_param = unpacker.unpack_query_params(request)
82
+
83
+ request.env[validator_option.params_key] = Committee::Utils.indifferent_hash
84
+ request.env[validator_option.params_key].merge!(Committee::Utils.deep_copy(query_param))
85
+ request.env[validator_option.params_key].merge!(Committee::Utils.deep_copy(request.env[validator_option.request_body_hash_key]))
86
+ request.env[validator_option.params_key].merge!(Committee::Utils.deep_copy(request.env[validator_option.path_hash_key]))
85
87
  end
86
88
 
87
89
  def copy_coerced_data_to_query_hash(request)
88
90
  return if request.env["rack.request.query_hash"].nil? || request.env["rack.request.query_hash"].empty?
89
91
 
92
+ query_hash_key = @validator_option.query_hash_key
93
+ return unless query_hash_key
94
+
95
+ request.env[query_hash_key] = {} unless request.env[query_hash_key]
90
96
  request.env["rack.request.query_hash"].keys.each do |k|
91
- request.env["rack.request.query_hash"][k] = request.env[validator_option.params_key][k]
97
+ request.env[query_hash_key][k] = request.env[validator_option.params_key][k]
92
98
  end
93
99
  end
94
100
  end