committee 0.4.14 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/committee-stub +1 -1
- data/lib/committee/errors.rb +1 -10
- data/lib/committee/middleware/base.rb +9 -1
- data/lib/committee/middleware/request_validation.rb +5 -9
- data/lib/committee/middleware/response_validation.rb +3 -19
- data/lib/committee/middleware/stub.rb +4 -5
- data/lib/committee/request_validator.rb +28 -0
- data/lib/committee/response_generator.rb +19 -13
- data/lib/committee/response_validator.rb +21 -88
- data/lib/committee/router.rb +10 -9
- data/lib/committee/test/methods.rb +15 -17
- data/lib/committee.rb +10 -3
- data/test/middleware/request_validation_test.rb +23 -43
- data/test/middleware/response_validation_test.rb +9 -27
- data/test/middleware/stub_test.rb +10 -1
- data/test/request_validator_test.rb +34 -0
- data/test/response_generator_test.rb +15 -15
- data/test/response_validator_test.rb +19 -110
- data/test/router_test.rb +6 -6
- data/test/test/methods_test.rb +7 -20
- data/test/test_helper.rb +4 -40
- metadata +14 -17
- data/lib/committee/param_validator.rb +0 -106
- data/lib/committee/schema.rb +0 -56
- data/lib/committee/validation.rb +0 -83
- data/test/param_validator_test.rb +0 -127
- data/test/performance/request_validation.rb +0 -55
- data/test/schema_test.rb +0 -36
@@ -0,0 +1,34 @@
|
|
1
|
+
require_relative "test_helper"
|
2
|
+
|
3
|
+
describe Committee::RequestValidator do
|
4
|
+
before do
|
5
|
+
@schema =
|
6
|
+
JsonSchema.parse!(MultiJson.decode(File.read("./test/data/schema.json")))
|
7
|
+
# POST /apps/:id
|
8
|
+
@link = @link = @schema.properties["app"].links[0]
|
9
|
+
end
|
10
|
+
|
11
|
+
it "passes through a valid request" do
|
12
|
+
params = {
|
13
|
+
"name" => "heroku-api",
|
14
|
+
}
|
15
|
+
call(params)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "detects a parameter of the wrong pattern" do
|
19
|
+
params = {
|
20
|
+
"name" => "%@!"
|
21
|
+
}
|
22
|
+
e = assert_raises(Committee::InvalidRequest) do
|
23
|
+
call(params)
|
24
|
+
end
|
25
|
+
message = %{Invalid request.\n\nAt "/schema/app": Expected string to match pattern "/^[a-z][a-z0-9-]{3,30}$/", value was: %@!.}
|
26
|
+
assert_equal message, e.message
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def call(params)
|
32
|
+
Committee::RequestValidator.new.call(@link, params)
|
33
|
+
end
|
34
|
+
end
|
@@ -2,31 +2,31 @@ require_relative "test_helper"
|
|
2
2
|
|
3
3
|
describe Committee::ResponseGenerator do
|
4
4
|
before do
|
5
|
-
@schema =
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
@schema =
|
6
|
+
JsonSchema.parse!(MultiJson.decode(File.read("./test/data/schema.json")))
|
7
|
+
# GET /apps/:id
|
8
|
+
@get_link = @link = @schema.properties["app"].links[2]
|
9
|
+
# GET /apps
|
10
|
+
@list_link = @schema.properties["app"].links[3]
|
11
11
|
end
|
12
12
|
|
13
13
|
it "generates string properties" do
|
14
|
-
data =
|
14
|
+
data = call
|
15
15
|
assert data["name"].is_a?(String)
|
16
16
|
end
|
17
17
|
|
18
18
|
it "generates non-string properties" do
|
19
|
-
data =
|
20
|
-
|
19
|
+
data = call
|
20
|
+
assert_includes [FalseClass, TrueClass], data["maintenance"].class
|
21
21
|
end
|
22
22
|
|
23
23
|
it "wraps list data in an array" do
|
24
|
-
@
|
25
|
-
|
26
|
-
@schema["app"],
|
27
|
-
@schema["app"]["links"][3]
|
28
|
-
)
|
29
|
-
data = @generator.call
|
24
|
+
@link = @list_link
|
25
|
+
data = call
|
30
26
|
assert data.is_a?(Array)
|
31
27
|
end
|
28
|
+
|
29
|
+
def call
|
30
|
+
Committee::ResponseGenerator.new.call(@link)
|
31
|
+
end
|
32
32
|
end
|
@@ -3,10 +3,16 @@ require_relative "test_helper"
|
|
3
3
|
describe Committee::ResponseValidator do
|
4
4
|
before do
|
5
5
|
@data = ValidApp.dup
|
6
|
-
@
|
6
|
+
@headers = {
|
7
|
+
"Content-Type" => "application/json"
|
8
|
+
}
|
9
|
+
@schema =
|
10
|
+
JsonSchema.parse!(MultiJson.decode(File.read("./test/data/schema.json")))
|
7
11
|
# GET /apps/:id
|
8
|
-
@
|
9
|
-
|
12
|
+
@get_link = @link = @schema.properties["app"].links[2]
|
13
|
+
# GET /apps
|
14
|
+
@list_link = @schema.properties["app"].links[3]
|
15
|
+
@type_schema = @schema.properties["app"]
|
10
16
|
end
|
11
17
|
|
12
18
|
it "passes through a valid response" do
|
@@ -15,132 +21,35 @@ describe Committee::ResponseValidator do
|
|
15
21
|
|
16
22
|
it "passes through a valid list response" do
|
17
23
|
@data = [@data]
|
18
|
-
|
19
|
-
@link_schema = @schema["app"]["links"][3]
|
20
|
-
call
|
21
|
-
end
|
22
|
-
|
23
|
-
it "passes through a valid list response with non-default title" do
|
24
|
-
@data = [@data]
|
25
|
-
@link_schema = @schema["app"]["links"][4]
|
24
|
+
@link = @list_link
|
26
25
|
call
|
27
26
|
end
|
28
27
|
|
29
28
|
it "detects an improperly formatted list response" do
|
30
|
-
|
31
|
-
@link_schema = @schema["app"]["links"][3]
|
29
|
+
@link = @list_link
|
32
30
|
e = assert_raises(Committee::InvalidResponse) { call }
|
33
31
|
message = "List endpoints must return an array of objects."
|
34
32
|
assert_equal message, e.message
|
35
33
|
end
|
36
34
|
|
37
|
-
it "detects
|
38
|
-
@
|
39
|
-
e = assert_raises(Committee::InvalidResponse) { call }
|
40
|
-
message = %r{Missing keys in response: name.}
|
41
|
-
assert_match message, e.message
|
42
|
-
end
|
43
|
-
|
44
|
-
it "detects extra keys in response" do
|
45
|
-
@data.merge!("tier" => "important")
|
35
|
+
it "detects an invalid response Content-Type" do
|
36
|
+
@headers = {}
|
46
37
|
e = assert_raises(Committee::InvalidResponse) { call }
|
47
|
-
message =
|
48
|
-
|
49
|
-
end
|
50
|
-
|
51
|
-
it "detects mismatched types" do
|
52
|
-
@data.merge!("maintenance" => "not-bool")
|
53
|
-
e = assert_raises(Committee::InvalidType) { call }
|
54
|
-
message = %{Invalid type at "maintenance": expected "not-bool" to be ["boolean"].}
|
55
|
-
assert_equal message, e.message
|
56
|
-
end
|
57
|
-
|
58
|
-
it "detects bad formats" do
|
59
|
-
@data.merge!("id" => "123")
|
60
|
-
e = assert_raises(Committee::InvalidFormat) { call }
|
61
|
-
message = %{Invalid format at "id": expected "123" to be "uuid".}
|
38
|
+
message =
|
39
|
+
%{"Content-Type" response header must be set to "application/json".}
|
62
40
|
assert_equal message, e.message
|
63
41
|
end
|
64
42
|
|
65
|
-
it "
|
43
|
+
it "raises errors generated by json_schema" do
|
66
44
|
@data.merge!("name" => "%@!")
|
67
|
-
e = assert_raises(Committee::
|
68
|
-
message = %{Invalid
|
69
|
-
assert_equal message, e.message
|
70
|
-
end
|
71
|
-
|
72
|
-
it "accepts date-time format without milliseconds" do
|
73
|
-
validator = Committee::ResponseValidator.new(
|
74
|
-
@data,
|
75
|
-
@schema,
|
76
|
-
@link_schema,
|
77
|
-
@schema["app"])
|
78
|
-
|
79
|
-
value = "2014-03-10T00:00:00Z"
|
80
|
-
assert_nil validator.check_format!("date-time", value, ["example"])
|
81
|
-
end
|
82
|
-
|
83
|
-
it "accepts date-time format with milliseconds" do
|
84
|
-
validator = Committee::ResponseValidator.new(
|
85
|
-
@data,
|
86
|
-
@schema,
|
87
|
-
@link_schema,
|
88
|
-
@schema["app"])
|
89
|
-
|
90
|
-
value = "2014-03-10T00:00:00.123Z"
|
91
|
-
assert_nil validator.check_format!("date-time", value, ["example"])
|
92
|
-
end
|
93
|
-
|
94
|
-
it "accepts a simple array" do
|
95
|
-
@data = ValidAccount.dup
|
96
|
-
@data["flags"] = @data["flags"].dup
|
97
|
-
@link_schema = @schema["account"]["links"][1]
|
98
|
-
@type_schema = @schema["account"]
|
99
|
-
|
100
|
-
call
|
101
|
-
end
|
102
|
-
|
103
|
-
it "validates an array of objects" do
|
104
|
-
@data = ValidAccount.dup
|
105
|
-
@data["credit_cards"] = @data["credit_cards"].dup
|
106
|
-
@link_schema = @schema["account"]["links"][0]
|
107
|
-
@type_schema = @schema["account"]
|
108
|
-
|
109
|
-
call
|
110
|
-
end
|
111
|
-
|
112
|
-
it "detects a simple array with an item of the wrong type" do
|
113
|
-
@data = ValidAccount.dup
|
114
|
-
@data["flags"] = @data["flags"].dup
|
115
|
-
@data["flags"] << false
|
116
|
-
@link_schema = @schema["account"]["links"][1]
|
117
|
-
@type_schema = @schema["account"]
|
118
|
-
|
119
|
-
e = assert_raises(Committee::InvalidType) { call }
|
120
|
-
message = %{Invalid type at "flags": expected false to be ["string"].}
|
121
|
-
assert_equal message, e.message
|
122
|
-
end
|
123
|
-
|
124
|
-
it "rejects an invalid pattern match" do
|
125
|
-
@data = ValidAccount.dup
|
126
|
-
@data["credit_cards"] = @data["credit_cards"].dup
|
127
|
-
@data["credit_cards"] << {"account_number" => "1234-1234-1234-HUGZ", "name" => "Rodney Mullen", "security_code" => 123}
|
128
|
-
@link_schema = @schema["account"]["links"][0]
|
129
|
-
@type_schema = @schema["account"]
|
130
|
-
|
131
|
-
e = assert_raises(Committee::InvalidPattern) { call }
|
132
|
-
message = %{Invalid pattern at "credit_cards:account_number": expected 1234-1234-1234-HUGZ to match "(?-mix:[0-9]{4}\\-[0-9]{4}\\-[0-9]{4}\\-[0-9]{4}$)".}
|
45
|
+
e = assert_raises(Committee::InvalidResponse) { call }
|
46
|
+
message = %{Invalid response.\n\nAt "/schema/app": Expected string to match pattern "/^[a-z][a-z0-9-]{3,30}$/", value was: %@!.}
|
133
47
|
assert_equal message, e.message
|
134
48
|
end
|
135
49
|
|
136
50
|
private
|
137
51
|
|
138
52
|
def call
|
139
|
-
Committee::ResponseValidator.new(
|
140
|
-
@data,
|
141
|
-
@schema,
|
142
|
-
@link_schema,
|
143
|
-
@type_schema
|
144
|
-
).call
|
53
|
+
Committee::ResponseValidator.new(@link).call(@headers, @data)
|
145
54
|
end
|
146
55
|
end
|
data/test/router_test.rb
CHANGED
@@ -2,25 +2,25 @@ require_relative "test_helper"
|
|
2
2
|
|
3
3
|
describe Committee::Router do
|
4
4
|
before do
|
5
|
-
data = File.read("./test/data/schema.json")
|
6
|
-
schema =
|
5
|
+
data = MultiJson.decode(File.read("./test/data/schema.json"))
|
6
|
+
schema = JsonSchema.parse!(data)
|
7
7
|
@router = Committee::Router.new(schema)
|
8
8
|
end
|
9
9
|
|
10
10
|
it "builds routes without parameters" do
|
11
|
-
refute_nil @router.routes?("GET", "/apps")
|
11
|
+
refute_nil @router.routes?("GET", "/apps")
|
12
12
|
end
|
13
13
|
|
14
14
|
it "builds routes with parameters" do
|
15
|
-
refute_nil @router.routes?("GET", "/apps/123")
|
15
|
+
refute_nil @router.routes?("GET", "/apps/123")
|
16
16
|
end
|
17
17
|
|
18
18
|
it "doesn't match anything on a /" do
|
19
|
-
assert_nil @router.routes?("GET", "/")
|
19
|
+
assert_nil @router.routes?("GET", "/")
|
20
20
|
end
|
21
21
|
|
22
22
|
it "takes a prefix" do
|
23
23
|
# this is a sociopathic example
|
24
|
-
refute_nil @router.routes?("GET", "/kpi/apps/123", prefix: "/kpi")
|
24
|
+
refute_nil @router.routes?("GET", "/kpi/apps/123", prefix: "/kpi")
|
25
25
|
end
|
26
26
|
end
|
data/test/test/methods_test.rb
CHANGED
@@ -13,20 +13,10 @@ describe Committee::Middleware::Stub do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
describe "#assert_schema_content_type" do
|
16
|
-
it "
|
17
|
-
|
18
|
-
get "/apps"
|
16
|
+
it "warns about deprecation" do
|
17
|
+
mock(Committee).warn_deprecated.with_any_args
|
19
18
|
assert_schema_content_type
|
20
19
|
end
|
21
|
-
|
22
|
-
it "detects an invalid response Content-Type" do
|
23
|
-
@app = new_rack_app(MultiJson.encode([ValidApp]), {})
|
24
|
-
get "/apps"
|
25
|
-
e = assert_raises(Committee::InvalidResponse) do
|
26
|
-
assert_schema_content_type
|
27
|
-
end
|
28
|
-
assert_match /response header must be set to/i, e.message
|
29
|
-
end
|
30
20
|
end
|
31
21
|
|
32
22
|
describe "#assert_schema_conform" do
|
@@ -45,15 +35,12 @@ describe Committee::Middleware::Stub do
|
|
45
35
|
assert_match /response header must be set to/i, e.message
|
46
36
|
end
|
47
37
|
|
48
|
-
it "
|
49
|
-
|
50
|
-
|
51
|
-
@app = new_rack_app(MultiJson.encode([
|
38
|
+
it "warns when sending a deprecated string" do
|
39
|
+
stub(self).schema_contents { File.read(schema_path) }
|
40
|
+
mock(Committee).warn_deprecated.with_any_args
|
41
|
+
@app = new_rack_app(MultiJson.encode([ValidApp]))
|
52
42
|
get "/apps"
|
53
|
-
|
54
|
-
assert_schema_conform
|
55
|
-
end
|
56
|
-
assert_match /missing keys/i, e.message
|
43
|
+
assert_schema_conform
|
57
44
|
end
|
58
45
|
end
|
59
46
|
|
data/test/test_helper.rb
CHANGED
@@ -1,48 +1,12 @@
|
|
1
1
|
require "minitest"
|
2
2
|
require "minitest/spec"
|
3
3
|
require "minitest/autorun"
|
4
|
-
|
5
|
-
require "
|
6
|
-
Bundler.require(:development)
|
4
|
+
require "rack/test"
|
5
|
+
require "rr"
|
7
6
|
|
8
7
|
require_relative "../lib/committee"
|
9
8
|
|
10
9
|
ValidApp = {
|
11
|
-
"
|
12
|
-
"
|
13
|
-
"created_at" => "2012-01-01T12:00:00Z",
|
14
|
-
"git_url" => "git@heroku.com/example.git",
|
15
|
-
"id" => "01234567-89ab-cdef-0123-456789abcdef",
|
16
|
-
"maintenance" => false,
|
17
|
-
"name" => "example",
|
18
|
-
"owner" => {
|
19
|
-
"email" => "username@example.com",
|
20
|
-
"id" => "01234567-89ab-cdef-0123-456789abcdef"
|
21
|
-
},
|
22
|
-
"region" => {
|
23
|
-
"id" => "01234567-89ab-cdef-0123-456789abcdef",
|
24
|
-
"name" => "us"
|
25
|
-
},
|
26
|
-
"released_at" => "2012-01-01T12:00:00Z",
|
27
|
-
"repo_size" => 0,
|
28
|
-
"slug_size" => 0,
|
29
|
-
"stack" => {
|
30
|
-
"id" => "01234567-89ab-cdef-0123-456789abcdef",
|
31
|
-
"name" => "cedar"
|
32
|
-
},
|
33
|
-
"updated_at" => "2012-01-01T12:00:00Z",
|
34
|
-
"web_url" => "http://example.herokuapp.com"
|
35
|
-
}.freeze
|
36
|
-
|
37
|
-
ValidAccount = {
|
38
|
-
"allow_tracking" => true,
|
39
|
-
"beta" => true,
|
40
|
-
"created_at" => "2012-01-01T12:00:00Z",
|
41
|
-
"email" => "username@example.com",
|
42
|
-
"id" => "01234567-89ab-cdef-0123-456789abcdef",
|
43
|
-
"last_login" => "2012-01-01T12:00:00Z",
|
44
|
-
"updated_at" => "2012-01-01T12:00:00Z",
|
45
|
-
"verified" => true,
|
46
|
-
"flags" => ["foo", "bar"],
|
47
|
-
"credit_cards" => [{"account_number" => "1234-1234-1234-1234", "name" => "Rodney Mullen", "security_code" => 123}]
|
10
|
+
"maintenance" => false,
|
11
|
+
"name" => "example",
|
48
12
|
}.freeze
|
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: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,10 +10,10 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2014-05-
|
13
|
+
date: 2014-05-21 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
|
-
name:
|
16
|
+
name: json_schema
|
17
17
|
requirement: !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
@@ -29,7 +29,7 @@ dependencies:
|
|
29
29
|
- !ruby/object:Gem::Version
|
30
30
|
version: '0.0'
|
31
31
|
- !ruby/object:Gem::Dependency
|
32
|
-
name:
|
32
|
+
name: multi_json
|
33
33
|
requirement: !ruby/object:Gem::Requirement
|
34
34
|
none: false
|
35
35
|
requirements:
|
@@ -45,21 +45,21 @@ dependencies:
|
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '0.0'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
48
|
+
name: rack
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
|
-
- - ! '
|
52
|
+
- - ! '>'
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
type: :
|
54
|
+
version: '0.0'
|
55
|
+
type: :runtime
|
56
56
|
prerelease: false
|
57
57
|
version_requirements: !ruby/object:Gem::Requirement
|
58
58
|
none: false
|
59
59
|
requirements:
|
60
|
-
- - ! '
|
60
|
+
- - ! '>'
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version: '0'
|
62
|
+
version: '0.0'
|
63
63
|
- !ruby/object:Gem::Dependency
|
64
64
|
name: rack-test
|
65
65
|
requirement: !ruby/object:Gem::Requirement
|
@@ -77,7 +77,7 @@ dependencies:
|
|
77
77
|
- !ruby/object:Gem::Version
|
78
78
|
version: '0'
|
79
79
|
- !ruby/object:Gem::Dependency
|
80
|
-
name:
|
80
|
+
name: rr
|
81
81
|
requirement: !ruby/object:Gem::Requirement
|
82
82
|
none: false
|
83
83
|
requirements:
|
@@ -106,25 +106,21 @@ files:
|
|
106
106
|
- lib/committee/middleware/request_validation.rb
|
107
107
|
- lib/committee/middleware/response_validation.rb
|
108
108
|
- lib/committee/middleware/stub.rb
|
109
|
-
- lib/committee/param_validator.rb
|
110
109
|
- lib/committee/request_unpacker.rb
|
110
|
+
- lib/committee/request_validator.rb
|
111
111
|
- lib/committee/response_generator.rb
|
112
112
|
- lib/committee/response_validator.rb
|
113
113
|
- lib/committee/router.rb
|
114
|
-
- lib/committee/schema.rb
|
115
114
|
- lib/committee/test/methods.rb
|
116
|
-
- lib/committee/validation.rb
|
117
115
|
- lib/committee.rb
|
118
116
|
- test/middleware/request_validation_test.rb
|
119
117
|
- test/middleware/response_validation_test.rb
|
120
118
|
- test/middleware/stub_test.rb
|
121
|
-
- test/param_validator_test.rb
|
122
|
-
- test/performance/request_validation.rb
|
123
119
|
- test/request_unpacker_test.rb
|
120
|
+
- test/request_validator_test.rb
|
124
121
|
- test/response_generator_test.rb
|
125
122
|
- test/response_validator_test.rb
|
126
123
|
- test/router_test.rb
|
127
|
-
- test/schema_test.rb
|
128
124
|
- test/test/methods_test.rb
|
129
125
|
- test/test_helper.rb
|
130
126
|
- bin/committee-stub
|
@@ -154,3 +150,4 @@ signing_key:
|
|
154
150
|
specification_version: 3
|
155
151
|
summary: A collection of Rack middleware to support JSON Schema.
|
156
152
|
test_files: []
|
153
|
+
has_rdoc:
|
@@ -1,106 +0,0 @@
|
|
1
|
-
module Committee
|
2
|
-
class ParamValidator
|
3
|
-
include Validation
|
4
|
-
|
5
|
-
def initialize(params, schema, link_schema, options = {})
|
6
|
-
@params = params
|
7
|
-
@schema = schema
|
8
|
-
@link_schema = link_schema
|
9
|
-
@allow_extra = options[:allow_extra]
|
10
|
-
end
|
11
|
-
|
12
|
-
def call
|
13
|
-
detect_missing!
|
14
|
-
detect_extra! if !@allow_extra
|
15
|
-
check_data!
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def all_keys
|
21
|
-
properties = @link_schema["schema"] && @link_schema["schema"]["properties"]
|
22
|
-
properties && properties.keys || []
|
23
|
-
end
|
24
|
-
|
25
|
-
def check_data!
|
26
|
-
return if !@link_schema["schema"] || !@link_schema["schema"]["properties"]
|
27
|
-
|
28
|
-
@link_schema["schema"]["properties"].each do |key, value|
|
29
|
-
# don't try to check this unless it was actually specificed
|
30
|
-
next unless @params.key?(key)
|
31
|
-
|
32
|
-
if value["type"] != ["array"]
|
33
|
-
definitions = find_definitions(value["$ref"])
|
34
|
-
try_match(key, @params[key], definitions)
|
35
|
-
else
|
36
|
-
# only assume one possible array definition for now
|
37
|
-
definitions = find_definitions(value["items"]["$ref"])
|
38
|
-
array_definition = definitions[0]
|
39
|
-
@params[key].each do |item|
|
40
|
-
# separate logic for a complex object that includes properties
|
41
|
-
if array_definition.key?("properties")
|
42
|
-
array_definition["properties"].each do |array_key, array_value|
|
43
|
-
return unless item.key?(array_key)
|
44
|
-
|
45
|
-
# @todo: this should really be recursive; only one array level is
|
46
|
-
# supported for now
|
47
|
-
item_definitions = find_definitions(array_value["$ref"])
|
48
|
-
try_match(array_key, item[array_key], item_definitions)
|
49
|
-
end
|
50
|
-
else
|
51
|
-
try_match(key, item, definitions)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def detect_extra!
|
59
|
-
extra = @params.keys - all_keys
|
60
|
-
if extra.count > 0
|
61
|
-
raise InvalidParams.new("Unknown params: #{extra.join(', ')}.")
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def detect_missing!
|
66
|
-
missing = required_keys - @params.keys
|
67
|
-
if missing.count > 0
|
68
|
-
raise InvalidParams.new("Require params: #{missing.join(', ')}.")
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def find_definitions(ref)
|
73
|
-
definition = @schema.find(ref)
|
74
|
-
if definition["anyOf"]
|
75
|
-
definition["anyOf"].map { |r| @schema.find(r["$ref"]) }
|
76
|
-
else
|
77
|
-
[definition]
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def required_keys
|
82
|
-
(@link_schema["schema"] && @link_schema["schema"]["required"]) || []
|
83
|
-
end
|
84
|
-
|
85
|
-
def try_match(key, value, definitions)
|
86
|
-
match = false
|
87
|
-
|
88
|
-
# try to match data against any possible definition
|
89
|
-
definitions.each do |definition|
|
90
|
-
if check_type(definition["type"], value, key) &&
|
91
|
-
check_format(definition["format"], value, key) &&
|
92
|
-
check_pattern(definition["pattern"], value, key)
|
93
|
-
match = true
|
94
|
-
next
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# if nothing was matched, throw error according to first definition
|
99
|
-
if !match && definition = definitions.first
|
100
|
-
check_type!(definition["type"], value, key)
|
101
|
-
check_format!(definition["format"], value, key)
|
102
|
-
check_pattern!(definition["pattern"], value, key)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
data/lib/committee/schema.rb
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
module Committee
|
2
|
-
class Schema
|
3
|
-
include Enumerable
|
4
|
-
|
5
|
-
def initialize(data)
|
6
|
-
@cache = {}
|
7
|
-
@schema = MultiJson.decode(data)
|
8
|
-
manifest_regex(@schema)
|
9
|
-
end
|
10
|
-
|
11
|
-
def [](type)
|
12
|
-
find(@schema["properties"][type]['$ref'])
|
13
|
-
end
|
14
|
-
|
15
|
-
def each
|
16
|
-
@schema["properties"].each do |type, ref|
|
17
|
-
yield(type, find(ref['$ref']))
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def find(ref)
|
22
|
-
cache(ref) do
|
23
|
-
parts = ref.split("/")
|
24
|
-
parts.shift if parts.first == "#"
|
25
|
-
pointer = @schema
|
26
|
-
parts.each do |p|
|
27
|
-
next unless pointer
|
28
|
-
pointer = pointer[p]
|
29
|
-
end
|
30
|
-
raise ReferenceNotFound, "Reference not found: #{ref}." if !pointer
|
31
|
-
pointer
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def cache(key)
|
38
|
-
if @cache[key]
|
39
|
-
@cache[key]
|
40
|
-
else
|
41
|
-
@cache[key] = yield
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def manifest_regex(schema_part)
|
46
|
-
schema_part["definitions"].each do |_, type_schema|
|
47
|
-
if type_schema.has_key?("definitions")
|
48
|
-
manifest_regex(type_schema)
|
49
|
-
end
|
50
|
-
if pattern = type_schema["pattern"]
|
51
|
-
type_schema["pattern"] = Regexp.new(pattern)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|