committee 1.14.1 → 1.15.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
  SHA1:
3
- metadata.gz: 6b93ed460e34afc046f016a0b28c53c221bb4eb5
4
- data.tar.gz: 0670a4037229f06312799901ade0e94bf416a95e
3
+ metadata.gz: d5fcb82a192f894e1baec1dcab89f081782d222f
4
+ data.tar.gz: 54d056b8be5b297b6a524166363f955db7a1bd15
5
5
  SHA512:
6
- metadata.gz: c64af87f69eeeb24ba0b6dd0e9baa873c436d67e452dfde3c432e318d3cf583ec536dd1faed3c136ce1e4d0a2b90aac17083b861492ce0ed518d24ea2ede4f36
7
- data.tar.gz: 9fcc322cc7e10fa8299fc0025dada82a5222c3546988737ed344f06d9e809ccf1c6a010a193d1e49378ba3c2767b0e340652793bcd8f22edf0d7c2590795a96e
6
+ metadata.gz: f22924efd2696d884eb499978cdb2a9f6e81ead9d25dacbe3ea331b9fb4d771886a4ccea1926fe2d09256886433a451fdbe25ef47cbe8d4c80a07a4157e0b9bc
7
+ data.tar.gz: db8d1aa50e4f4fa854bda1d5484df09e7262801bd845195c1340a718fc6d0792666360698ea2fe8722f1c57a287fcfb4b1f0258706032f47a2ef7cceaffd7df9
data/lib/committee.rb CHANGED
@@ -3,6 +3,7 @@ require "json_schema"
3
3
  require "rack"
4
4
 
5
5
  require_relative "committee/errors"
6
+ require_relative "committee/query_params_coercer"
6
7
  require_relative "committee/request_unpacker"
7
8
  require_relative "committee/request_validator"
8
9
  require_relative "committee/response_generator"
@@ -2,17 +2,29 @@ module Committee::Middleware
2
2
  class RequestValidation < Base
3
3
  def initialize(app, options={})
4
4
  super
5
- @allow_form_params = options.fetch(:allow_form_params, true)
6
- @allow_query_params = options.fetch(:allow_query_params, true)
7
- @check_content_type = options.fetch(:check_content_type, true)
8
- @optimistic_json = options.fetch(:optimistic_json, false)
9
- @strict = options[:strict]
5
+ @allow_form_params = options.fetch(:allow_form_params, true)
6
+ @allow_query_params = options.fetch(:allow_query_params, true)
7
+ @check_content_type = options.fetch(:check_content_type, true)
8
+ @optimistic_json = options.fetch(:optimistic_json, false)
9
+ @coerce_query_params = options.fetch(:coerce_query_params, false)
10
+ @strict = options[:strict]
10
11
 
11
12
  # deprecated
12
13
  @allow_extra = options[:allow_extra]
13
14
  end
14
15
 
15
16
  def handle(request)
17
+ link = @router.find_request_link(request)
18
+
19
+ if link && @coerce_query_params && !request.GET.nil? && !link.schema.nil?
20
+ request.env["rack.request.query_hash"].merge!(
21
+ Committee::QueryParamsCoercer.new(
22
+ request.GET,
23
+ link.schema
24
+ ).call
25
+ )
26
+ end
27
+
16
28
  request.env[@params_key] = Committee::RequestUnpacker.new(
17
29
  request,
18
30
  allow_form_params: @allow_form_params,
@@ -20,7 +32,7 @@ module Committee::Middleware
20
32
  optimistic_json: @optimistic_json
21
33
  ).call
22
34
 
23
- if link = @router.find_request_link(request)
35
+ if link
24
36
  validator = Committee::RequestValidator.new(link, check_content_type: @check_content_type)
25
37
  validator.call(request, request.env[@params_key])
26
38
  @app.call(request.env)
@@ -0,0 +1,45 @@
1
+ # Attempts to coerce params given in the query hash (which are all strings) into
2
+ # the types specified by the schema.
3
+ # Currently supported types: null, integer, number and boolean.
4
+ # +call+ returns a hash of all params which could be coerced - coercion errors
5
+ # are simply ignored and expected to be handled later by schema validation.
6
+ module Committee
7
+ class QueryParamsCoercer
8
+ def initialize(query_hash, schema)
9
+ @query_hash = query_hash
10
+ @schema = schema
11
+ end
12
+
13
+ def call
14
+ coerced = {}
15
+ @schema.properties.each do |k, s|
16
+ original_val = @query_hash[k]
17
+ unless original_val.nil?
18
+ s.type.each do |to_type|
19
+ case to_type
20
+ when "null"
21
+ coerced[k] = nil if original_val.empty?
22
+ when "integer"
23
+ begin
24
+ coerced[k] = Integer(original_val)
25
+ rescue ArgumentError => e
26
+ raise e unless e.message =~ /invalid value for Integer/
27
+ end
28
+ when "number"
29
+ begin
30
+ coerced[k] = Float(original_val)
31
+ rescue ArgumentError => e
32
+ raise e unless e.message =~ /invalid value for Float/
33
+ end
34
+ when "boolean"
35
+ coerced[k] = true if original_val == "true"
36
+ coerced[k] = false if original_val == "false"
37
+ end
38
+ break if coerced.key?(k)
39
+ end
40
+ end
41
+ end
42
+ coerced
43
+ end
44
+ end
45
+ end
@@ -94,6 +94,21 @@ describe Committee::Middleware::RequestValidation do
94
94
  assert_equal 200, last_response.status
95
95
  end
96
96
 
97
+ it "optionally coerces query params" do
98
+ @app = new_rack_app(coerce_query_params: true)
99
+ header "Content-Type", "application/json"
100
+ get "/search/apps", {"per_page" => "10", "query" => "cloudnasium"}
101
+ assert_equal 200, last_response.status
102
+ end
103
+
104
+ it "still raises an error if query param coercion is not possible" do
105
+ @app = new_rack_app(coerce_query_params: true)
106
+ header "Content-Type", "application/json"
107
+ get "/search/apps", {"per_page" => "foo", "query" => "cloudnasium"}
108
+ assert_equal 400, last_response.status
109
+ assert_match /invalid request/i, last_response.body
110
+ end
111
+
97
112
  private
98
113
 
99
114
  def new_rack_app(options = {})
@@ -0,0 +1,70 @@
1
+ require_relative "test_helper"
2
+
3
+ describe Committee::QueryParamsCoercer do
4
+ before do
5
+ @schema =
6
+ JsonSchema.parse!(JSON.parse(File.read("./test/data/schema.json")))
7
+ @schema.expand_references!
8
+ # GET /search/apps
9
+ @link = @link = @schema.properties["app"].links[5]
10
+ end
11
+
12
+ it "doesn't coerce params not in the schema" do
13
+ data = {"owner" => "admin"}
14
+ assert_equal({}, call(data))
15
+ end
16
+
17
+ it "skips values for string param" do
18
+ data = {"name" => "foo"}
19
+ assert_equal({}, call(data))
20
+ end
21
+
22
+ it "coerces valid values for boolean param" do
23
+ data = {"deleted" => "true"}
24
+ assert_equal({"deleted" => true}, call(data))
25
+ data = {"deleted" => "false"}
26
+ assert_equal({"deleted" => false}, call(data))
27
+ end
28
+
29
+ it "skips invalid values for boolean param" do
30
+ data = {"deleted" => "foo"}
31
+ assert_equal({}, call(data))
32
+ end
33
+
34
+ it "coerces valid values for integer param" do
35
+ data = {"per_page" => "3"}
36
+ assert_equal({"per_page" => 3}, call(data))
37
+ end
38
+
39
+ it "skips invalid values for integer param" do
40
+ data = {"per_page" => "3.5"}
41
+ assert_equal({}, call(data))
42
+ data = {"per_page" => "false"}
43
+ assert_equal({}, call(data))
44
+ data = {"per_page" => ""}
45
+ assert_equal({}, call(data))
46
+ end
47
+
48
+ it "coerces valid values for number param" do
49
+ data = {"threshold" => "3"}
50
+ assert_equal({"threshold" => 3.0}, call(data))
51
+ data = {"threshold" => "3.5"}
52
+ assert_equal({"threshold" => 3.5}, call(data))
53
+ end
54
+
55
+ it "skips invalid values for number param" do
56
+ data = {"threshold" => "false"}
57
+ assert_equal({}, call(data))
58
+ end
59
+
60
+ it "coerces valid values for null param" do
61
+ data = {"threshold" => ""}
62
+ assert_equal({"threshold" => nil}, call(data))
63
+ end
64
+
65
+ private
66
+
67
+ def call(data)
68
+ Committee::QueryParamsCoercer.new(data, @link.schema).call
69
+ end
70
+ end
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: 1.14.1
4
+ version: 1.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandur
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-05-26 00:00:00.000000000 Z
12
+ date: 2016-09-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json_schema
@@ -117,6 +117,7 @@ files:
117
117
  - lib/committee/middleware/request_validation.rb
118
118
  - lib/committee/middleware/response_validation.rb
119
119
  - lib/committee/middleware/stub.rb
120
+ - lib/committee/query_params_coercer.rb
120
121
  - lib/committee/request_unpacker.rb
121
122
  - lib/committee/request_validator.rb
122
123
  - lib/committee/response_generator.rb
@@ -128,6 +129,7 @@ files:
128
129
  - test/middleware/request_validation_test.rb
129
130
  - test/middleware/response_validation_test.rb
130
131
  - test/middleware/stub_test.rb
132
+ - test/query_params_coercer_test.rb
131
133
  - test/request_unpacker_test.rb
132
134
  - test/request_validator_test.rb
133
135
  - test/response_generator_test.rb