json-schema-ouidou 2.9.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 +7 -0
- data/LICENSE.md +19 -0
- data/README.md +496 -0
- data/lib/json-schema/attribute.rb +57 -0
- data/lib/json-schema/attributes/additionalitems.rb +28 -0
- data/lib/json-schema/attributes/additionalproperties.rb +58 -0
- data/lib/json-schema/attributes/allof.rb +39 -0
- data/lib/json-schema/attributes/anyof.rb +47 -0
- data/lib/json-schema/attributes/dependencies.rb +38 -0
- data/lib/json-schema/attributes/dependencies_v4.rb +11 -0
- data/lib/json-schema/attributes/disallow.rb +12 -0
- data/lib/json-schema/attributes/divisibleby.rb +22 -0
- data/lib/json-schema/attributes/enum.rb +24 -0
- data/lib/json-schema/attributes/extends.rb +48 -0
- data/lib/json-schema/attributes/format.rb +14 -0
- data/lib/json-schema/attributes/formats/custom.rb +21 -0
- data/lib/json-schema/attributes/formats/date.rb +25 -0
- data/lib/json-schema/attributes/formats/date_time.rb +34 -0
- data/lib/json-schema/attributes/formats/date_time_v4.rb +15 -0
- data/lib/json-schema/attributes/formats/ip.rb +41 -0
- data/lib/json-schema/attributes/formats/time.rb +22 -0
- data/lib/json-schema/attributes/formats/uri.rb +18 -0
- data/lib/json-schema/attributes/items.rb +27 -0
- data/lib/json-schema/attributes/limit.rb +52 -0
- data/lib/json-schema/attributes/limits/items.rb +15 -0
- data/lib/json-schema/attributes/limits/length.rb +15 -0
- data/lib/json-schema/attributes/limits/max_items.rb +15 -0
- data/lib/json-schema/attributes/limits/max_length.rb +15 -0
- data/lib/json-schema/attributes/limits/max_properties.rb +15 -0
- data/lib/json-schema/attributes/limits/maximum.rb +15 -0
- data/lib/json-schema/attributes/limits/maximum_inclusive.rb +11 -0
- data/lib/json-schema/attributes/limits/min_items.rb +15 -0
- data/lib/json-schema/attributes/limits/min_length.rb +15 -0
- data/lib/json-schema/attributes/limits/min_properties.rb +15 -0
- data/lib/json-schema/attributes/limits/minimum.rb +15 -0
- data/lib/json-schema/attributes/limits/minimum_inclusive.rb +11 -0
- data/lib/json-schema/attributes/limits/numeric.rb +16 -0
- data/lib/json-schema/attributes/limits/properties.rb +15 -0
- data/lib/json-schema/attributes/maxdecimal.rb +18 -0
- data/lib/json-schema/attributes/multipleof.rb +11 -0
- data/lib/json-schema/attributes/not.rb +30 -0
- data/lib/json-schema/attributes/oneof.rb +56 -0
- data/lib/json-schema/attributes/pattern.rb +18 -0
- data/lib/json-schema/attributes/patternproperties.rb +22 -0
- data/lib/json-schema/attributes/properties.rb +66 -0
- data/lib/json-schema/attributes/properties_optional.rb +26 -0
- data/lib/json-schema/attributes/properties_v4.rb +13 -0
- data/lib/json-schema/attributes/ref.rb +61 -0
- data/lib/json-schema/attributes/required.rb +28 -0
- data/lib/json-schema/attributes/type.rb +73 -0
- data/lib/json-schema/attributes/type_v4.rb +29 -0
- data/lib/json-schema/attributes/uniqueitems.rb +20 -0
- data/lib/json-schema/errors/custom_format_error.rb +6 -0
- data/lib/json-schema/errors/json_load_error.rb +6 -0
- data/lib/json-schema/errors/json_parse_error.rb +6 -0
- data/lib/json-schema/errors/schema_error.rb +6 -0
- data/lib/json-schema/errors/schema_parse_error.rb +8 -0
- data/lib/json-schema/errors/uri_error.rb +6 -0
- data/lib/json-schema/errors/validation_error.rb +46 -0
- data/lib/json-schema/schema/reader.rb +140 -0
- data/lib/json-schema/schema/validator.rb +40 -0
- data/lib/json-schema/schema.rb +62 -0
- data/lib/json-schema/util/array_set.rb +20 -0
- data/lib/json-schema/util/uri.rb +110 -0
- data/lib/json-schema/util/uuid.rb +284 -0
- data/lib/json-schema/validator.rb +609 -0
- data/lib/json-schema/validators/draft1.rb +45 -0
- data/lib/json-schema/validators/draft2.rb +46 -0
- data/lib/json-schema/validators/draft3.rb +50 -0
- data/lib/json-schema/validators/draft4.rb +56 -0
- data/lib/json-schema/validators/draft6.rb +56 -0
- data/lib/json-schema/validators/hyper-draft1.rb +13 -0
- data/lib/json-schema/validators/hyper-draft2.rb +13 -0
- data/lib/json-schema/validators/hyper-draft3.rb +13 -0
- data/lib/json-schema/validators/hyper-draft4.rb +13 -0
- data/lib/json-schema/validators/hyper-draft6.rb +13 -0
- data/lib/json-schema.rb +18 -0
- data/resources/draft-01.json +155 -0
- data/resources/draft-02.json +166 -0
- data/resources/draft-03.json +174 -0
- data/resources/draft-04.json +150 -0
- data/resources/draft-06.json +150 -0
- metadata +197 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 229c79fe08ec97502b0d3d7fb9384655af26b050fdc0b545ae4a286684cf130b
|
4
|
+
data.tar.gz: 9e1777a533de9c1abab5bd537f28ef0ed7000da0368558847e314e0f258a18bf
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1ce322cce67da1ef9094291fc34f537135ce26af2f0c3bd292a9a4775404b6a6d866d846e9a7e982c8589292b9ae4510af3d2ac6b6dd5e148f6a1f0a66b1b818
|
7
|
+
data.tar.gz: c53a0aed220852d9bbe67faf49a5cfd51310eb4b77729a4a5f64899fa66e2895945e46164d3cc64f3f7881c42d46827e0c0de82223b57585a5a5374577198cce
|
data/LICENSE.md
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2010-2011, Lookingglass Cyber Solutions
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,496 @@
|
|
1
|
+
# Ruby JSON Schema Validator
|
2
|
+
|
3
|
+
[](https://github.com/voxpupuli/json-schema/blob/master/LICENSE)
|
4
|
+
[](https://github.com/voxpupuli/json-schema/actions/workflows/test.yml)
|
5
|
+
[](https://github.com/voxpupuli/json-schema/actions/workflows/release.yml)
|
6
|
+
[](https://rubygems.org/gems/json-schema)
|
7
|
+
[](https://rubygems.org/gems/json-schema)
|
8
|
+
[](#transfer-notice)
|
9
|
+
|
10
|
+
This library is intended to provide Ruby with an interface for validating JSON
|
11
|
+
objects against a JSON schema conforming to [JSON Schema Draft
|
12
|
+
4](http://tools.ietf.org/html/draft-zyp-json-schema-04). Legacy support for
|
13
|
+
[JSON Schema Draft 3](http://tools.ietf.org/html/draft-zyp-json-schema-03),
|
14
|
+
[JSON Schema Draft 2](http://tools.ietf.org/html/draft-zyp-json-schema-02), and
|
15
|
+
[JSON Schema Draft 1](http://tools.ietf.org/html/draft-zyp-json-schema-01) is
|
16
|
+
also included.
|
17
|
+
|
18
|
+
Additional Resources
|
19
|
+
--------------------
|
20
|
+
|
21
|
+
- [Google Groups](https://groups.google.com/forum/#!forum/ruby-json-schema)
|
22
|
+
- #ruby-json-schema on chat.freenode.net
|
23
|
+
|
24
|
+
Version 2.0.0 Upgrade Notes
|
25
|
+
---------------------------
|
26
|
+
|
27
|
+
Please be aware that the upgrade to version 2.0.0 will use Draft-04 **by
|
28
|
+
default**, so schemas that do not declare a validator using the `$schema`
|
29
|
+
keyword will use Draft-04 now instead of Draft-03. This is the reason for the
|
30
|
+
major version upgrade.
|
31
|
+
|
32
|
+
Installation
|
33
|
+
------------
|
34
|
+
|
35
|
+
From rubygems.org:
|
36
|
+
|
37
|
+
```sh
|
38
|
+
gem install json-schema
|
39
|
+
```
|
40
|
+
|
41
|
+
From the git repo:
|
42
|
+
|
43
|
+
```sh
|
44
|
+
$ gem build json-schema.gemspec
|
45
|
+
$ gem install json-schema-2.5.2.gem
|
46
|
+
```
|
47
|
+
|
48
|
+
Validation
|
49
|
+
-----
|
50
|
+
|
51
|
+
Three base validation methods exist:
|
52
|
+
|
53
|
+
1. `validate`: returns a boolean on whether a validation attempt passes
|
54
|
+
2. `validate!`: throws a `JSON::Schema::ValidationError` with an appropriate message/trace on where the validation failed
|
55
|
+
3. `fully_validate`: builds an array of validation errors return when validation is complete
|
56
|
+
|
57
|
+
All methods take two arguments, which can be either a JSON string, a file
|
58
|
+
containing JSON, or a Ruby object representing JSON data. The first argument to
|
59
|
+
these methods is always the schema, the second is always the data to validate.
|
60
|
+
An optional third options argument is also accepted; available options are used
|
61
|
+
in the examples below.
|
62
|
+
|
63
|
+
By default, the validator uses the [JSON Schema Draft
|
64
|
+
4](http://tools.ietf.org/html/draft-zyp-json-schema-04) specification for
|
65
|
+
validation; however, the user is free to specify additional specifications or
|
66
|
+
extend existing ones. Legacy support for Draft 1, Draft 2, and Draft 3 is
|
67
|
+
included by either passing an optional `:version` parameter to the `validate`
|
68
|
+
method (set either as `:draft1` or `draft2`), or by declaring the `$schema`
|
69
|
+
attribute in the schema and referencing the appropriate specification URI. Note
|
70
|
+
that the `$schema` attribute takes precedence over the `:version` option during
|
71
|
+
parsing and validation.
|
72
|
+
|
73
|
+
For further information on json schema itself refer to <a
|
74
|
+
href="http://spacetelescope.github.io/understanding-json-schema/">Understanding
|
75
|
+
JSON Schema</a>.
|
76
|
+
|
77
|
+
Basic Usage
|
78
|
+
--------------
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
require "json-schema"
|
82
|
+
|
83
|
+
schema = {
|
84
|
+
"type" => "object",
|
85
|
+
"required" => ["a"],
|
86
|
+
"properties" => {
|
87
|
+
"a" => {"type" => "integer"}
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
#
|
92
|
+
# validate ruby objects against a ruby schema
|
93
|
+
#
|
94
|
+
|
95
|
+
# => true
|
96
|
+
JSON::Validator.validate(schema, { "a" => 5 })
|
97
|
+
# => false
|
98
|
+
JSON::Validator.validate(schema, {})
|
99
|
+
|
100
|
+
#
|
101
|
+
# validate a json string against a json schema file
|
102
|
+
#
|
103
|
+
|
104
|
+
require "json"
|
105
|
+
File.write("schema.json", JSON.dump(schema))
|
106
|
+
|
107
|
+
# => true
|
108
|
+
JSON::Validator.validate('schema.json', '{ "a": 5 }')
|
109
|
+
|
110
|
+
#
|
111
|
+
# raise an error when validation fails
|
112
|
+
#
|
113
|
+
|
114
|
+
# => "The property '#/a' of type String did not match the following type: integer"
|
115
|
+
begin
|
116
|
+
JSON::Validator.validate!(schema, { "a" => "taco" })
|
117
|
+
rescue JSON::Schema::ValidationError => e
|
118
|
+
e.message
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# return an array of error messages when validation fails
|
123
|
+
#
|
124
|
+
|
125
|
+
# => ["The property '#/a' of type String did not match the following type: integer in schema 18a1ffbb-4681-5b00-bd15-2c76aee4b28f"]
|
126
|
+
JSON::Validator.fully_validate(schema, { "a" => "taco" })
|
127
|
+
```
|
128
|
+
|
129
|
+
Advanced Options
|
130
|
+
-----------------
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
require "json-schema"
|
134
|
+
|
135
|
+
schema = {
|
136
|
+
"type"=>"object",
|
137
|
+
"required" => ["a"],
|
138
|
+
"properties" => {
|
139
|
+
"a" => {
|
140
|
+
"type" => "integer",
|
141
|
+
"default" => 42
|
142
|
+
},
|
143
|
+
"b" => {
|
144
|
+
"type" => "object",
|
145
|
+
"properties" => {
|
146
|
+
"x" => {
|
147
|
+
"type" => "integer"
|
148
|
+
}
|
149
|
+
}
|
150
|
+
}
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
154
|
+
#
|
155
|
+
# with the `:list` option, a list can be validated against a schema that represents the individual objects
|
156
|
+
#
|
157
|
+
|
158
|
+
# => true
|
159
|
+
JSON::Validator.validate(schema, [{"a" => 1}, {"a" => 2}, {"a" => 3}], :list => true)
|
160
|
+
# => false
|
161
|
+
JSON::Validator.validate(schema, [{"a" => 1}, {"a" => 2}, {"a" => 3}])
|
162
|
+
|
163
|
+
#
|
164
|
+
# with the `:errors_as_objects` option, `#fully_validate` returns errors as hashes instead of strings
|
165
|
+
#
|
166
|
+
|
167
|
+
# => [{:schema=>#<Addressable::URI:0x3ffa69cbeed8 URI:18a1ffbb-4681-5b00-bd15-2c76aee4b28f>, :fragment=>"#/a", :message=>"The property '#/a' of type String did not match the following type: integer in schema 18a1ffbb-4681-5b00-bd15-2c76aee4b28f", :failed_attribute=>"TypeV4"}]
|
168
|
+
JSON::Validator.fully_validate(schema, { "a" => "taco" }, :errors_as_objects => true)
|
169
|
+
|
170
|
+
#
|
171
|
+
# with the `:strict` option, all properties are considered to have `"required": true` and all objects `"additionalProperties": false`
|
172
|
+
#
|
173
|
+
|
174
|
+
# => true
|
175
|
+
JSON::Validator.validate(schema, { "a" => 1, "b" => { "x" => 2 } }, :strict => true)
|
176
|
+
# => false
|
177
|
+
JSON::Validator.validate(schema, { "a" => 1, "b" => { "x" => 2 }, "c" => 3 }, :strict => true)
|
178
|
+
# => false
|
179
|
+
JSON::Validator.validate(schema, { "a" => 1 }, :strict => true)
|
180
|
+
|
181
|
+
#
|
182
|
+
# with the `:fragment` option, only a fragment of the schema is used for validation
|
183
|
+
#
|
184
|
+
|
185
|
+
# => true
|
186
|
+
JSON::Validator.validate(schema, { "x" => 1 }, :fragment => "#/properties/b")
|
187
|
+
# => false
|
188
|
+
JSON::Validator.validate(schema, { "x" => 1 })
|
189
|
+
|
190
|
+
#
|
191
|
+
# with the `:validate_schema` option, the schema is validated (against the json schema spec) before the json is validated (against the specified schema)
|
192
|
+
#
|
193
|
+
|
194
|
+
# => true
|
195
|
+
JSON::Validator.validate(schema, { "a" => 1 }, :validate_schema => true)
|
196
|
+
# => false
|
197
|
+
JSON::Validator.validate({ "required" => true }, { "a" => 1 }, :validate_schema => true)
|
198
|
+
|
199
|
+
#
|
200
|
+
# with the `:insert_defaults` option, any undefined values in the json that have a default in the schema are replaced with the default before validation
|
201
|
+
#
|
202
|
+
|
203
|
+
# => true
|
204
|
+
JSON::Validator.validate(schema, {}, :insert_defaults => true)
|
205
|
+
# => false
|
206
|
+
JSON::Validator.validate(schema, {})
|
207
|
+
|
208
|
+
#
|
209
|
+
# with the `:version` option, schemas conforming to older drafts of the json schema spec can be used
|
210
|
+
#
|
211
|
+
|
212
|
+
v2_schema = {
|
213
|
+
"type" => "object",
|
214
|
+
"properties" => {
|
215
|
+
"a" => {
|
216
|
+
"type" => "integer"
|
217
|
+
}
|
218
|
+
}
|
219
|
+
}
|
220
|
+
|
221
|
+
# => false
|
222
|
+
JSON::Validator.validate(v2_schema, {}, :version => :draft2)
|
223
|
+
# => true
|
224
|
+
JSON::Validator.validate(v2_schema, {})
|
225
|
+
|
226
|
+
#
|
227
|
+
# with the `:parse_data` option set to false, the json must be a parsed ruby object (not a json text, a uri or a file path)
|
228
|
+
#
|
229
|
+
|
230
|
+
# => true
|
231
|
+
JSON::Validator.validate(schema, { "a" => 1 }, :parse_data => false)
|
232
|
+
# => false
|
233
|
+
JSON::Validator.validate(schema, '{ "a": 1 }', :parse_data => false)
|
234
|
+
|
235
|
+
#
|
236
|
+
# with the `:json` option, the json must be an unparsed json text (not a hash, a uri or a file path)
|
237
|
+
#
|
238
|
+
|
239
|
+
# => true
|
240
|
+
JSON::Validator.validate(schema, '{ "a": 1 }', :json => true)
|
241
|
+
# => "no implicit conversion of Hash into String"
|
242
|
+
begin
|
243
|
+
JSON::Validator.validate(schema, { "a" => 1 }, :json => true)
|
244
|
+
rescue TypeError => e
|
245
|
+
e.message
|
246
|
+
end
|
247
|
+
|
248
|
+
#
|
249
|
+
# with the `:uri` option, the json must be a uri or file path (not a hash or a json text)
|
250
|
+
#
|
251
|
+
|
252
|
+
File.write("data.json", '{ "a": 1 }')
|
253
|
+
|
254
|
+
# => true
|
255
|
+
JSON::Validator.validate(schema, "data.json", :uri => true)
|
256
|
+
# => "Can't convert Hash into String."
|
257
|
+
begin
|
258
|
+
JSON::Validator.validate(schema, { "a" => 1 }, :uri => true)
|
259
|
+
rescue TypeError => e
|
260
|
+
e.message
|
261
|
+
end
|
262
|
+
|
263
|
+
#
|
264
|
+
# with the `:clear_cache` option set to true, the internal cache of schemas is
|
265
|
+
# cleared after validation (otherwise schemas are cached for efficiency)
|
266
|
+
#
|
267
|
+
|
268
|
+
File.write("schema.json", v2_schema.to_json)
|
269
|
+
|
270
|
+
# => true
|
271
|
+
JSON::Validator.validate("schema.json", {})
|
272
|
+
|
273
|
+
File.write("schema.json", schema.to_json)
|
274
|
+
|
275
|
+
# => true
|
276
|
+
JSON::Validator.validate("schema.json", {}, :clear_cache => true)
|
277
|
+
|
278
|
+
# => false
|
279
|
+
JSON::Validator.validate("schema.json", {})
|
280
|
+
```
|
281
|
+
|
282
|
+
Extending Schemas
|
283
|
+
-----------------
|
284
|
+
|
285
|
+
For this example, we are going to extend the [JSON Schema Draft
|
286
|
+
3](http://tools.ietf.org/html/draft-zyp-json-schema-03) specification by adding
|
287
|
+
a 'bitwise-and' property for validation.
|
288
|
+
|
289
|
+
```ruby
|
290
|
+
require "json-schema"
|
291
|
+
|
292
|
+
class BitwiseAndAttribute < JSON::Schema::Attribute
|
293
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
294
|
+
if data.is_a?(Integer) && data & current_schema.schema['bitwise-and'].to_i == 0
|
295
|
+
message = "The property '#{build_fragment(fragments)}' did not evaluate to true when bitwise-AND'd with #{current_schema.schema['bitwise-or']}"
|
296
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
class ExtendedSchema < JSON::Schema::Draft3
|
302
|
+
def initialize
|
303
|
+
super
|
304
|
+
@attributes["bitwise-and"] = BitwiseAndAttribute
|
305
|
+
@uri = JSON::Util::URI.parse("http://test.com/test.json")
|
306
|
+
@names = ["http://test.com/test.json"]
|
307
|
+
end
|
308
|
+
|
309
|
+
JSON::Validator.register_validator(self.new)
|
310
|
+
end
|
311
|
+
|
312
|
+
schema = {
|
313
|
+
"$schema" => "http://test.com/test.json",
|
314
|
+
"properties" => {
|
315
|
+
"a" => {
|
316
|
+
"bitwise-and" => 1
|
317
|
+
},
|
318
|
+
"b" => {
|
319
|
+
"type" => "string"
|
320
|
+
}
|
321
|
+
}
|
322
|
+
}
|
323
|
+
|
324
|
+
data = {
|
325
|
+
"a" => 0
|
326
|
+
}
|
327
|
+
|
328
|
+
data = {"a" => 1, "b" => "taco"}
|
329
|
+
JSON::Validator.validate(schema,data) # => true
|
330
|
+
data = {"a" => 1, "b" => 5}
|
331
|
+
JSON::Validator.validate(schema,data) # => false
|
332
|
+
data = {"a" => 0, "b" => "taco"}
|
333
|
+
JSON::Validator.validate(schema,data) # => false
|
334
|
+
```
|
335
|
+
|
336
|
+
Custom format validation
|
337
|
+
------------------------
|
338
|
+
|
339
|
+
The JSON schema standard allows custom formats in schema definitions which
|
340
|
+
should be ignored by validators that do not support them. JSON::Schema allows
|
341
|
+
registering procs as custom format validators which receive the value to be
|
342
|
+
checked as parameter and must raise a `JSON::Schema::CustomFormatError` to
|
343
|
+
indicate a format violation. The error message will be prepended by the property
|
344
|
+
name, e.g. [The property '#a']()
|
345
|
+
|
346
|
+
```ruby
|
347
|
+
require "json-schema"
|
348
|
+
|
349
|
+
format_proc = -> value {
|
350
|
+
raise JSON::Schema::CustomFormatError.new("must be 42") unless value == "42"
|
351
|
+
}
|
352
|
+
|
353
|
+
# register the proc for format 'the-answer' for draft4 schema
|
354
|
+
JSON::Validator.register_format_validator("the-answer", format_proc, ["draft4"])
|
355
|
+
|
356
|
+
# omitting the version parameter uses ["draft1", "draft2", "draft3", "draft4"] as default
|
357
|
+
JSON::Validator.register_format_validator("the-answer", format_proc)
|
358
|
+
|
359
|
+
# deregistering the custom validator
|
360
|
+
# (also ["draft1", "draft2", "draft3", "draft4"] as default version)
|
361
|
+
JSON::Validator.deregister_format_validator('the-answer', ["draft4"])
|
362
|
+
|
363
|
+
# shortcut to restore the default formats for validators (same default as before)
|
364
|
+
JSON::Validator.restore_default_formats(["draft4"])
|
365
|
+
|
366
|
+
# with the validator registered as above, the following results in
|
367
|
+
# ["The property '#a' must be 42"] as returned errors
|
368
|
+
schema = {
|
369
|
+
"$schema" => "http://json-schema.org/draft-04/schema#",
|
370
|
+
"properties" => {
|
371
|
+
"a" => {
|
372
|
+
"type" => "string",
|
373
|
+
"format" => "the-answer",
|
374
|
+
}
|
375
|
+
}
|
376
|
+
}
|
377
|
+
errors = JSON::Validator.fully_validate(schema, {"a" => "23"})
|
378
|
+
```
|
379
|
+
|
380
|
+
Validating a JSON Schema
|
381
|
+
------------------------
|
382
|
+
|
383
|
+
To validate that a JSON Schema conforms to the JSON Schema standard,
|
384
|
+
you need to validate your schema against the metaschema for the appropriate
|
385
|
+
JSON Schema Draft. All of the normal validation methods can be used
|
386
|
+
for this. First retrieve the appropriate metaschema from the internal
|
387
|
+
cache (using `JSON::Validator.validator_for_name()` or
|
388
|
+
`JSON::Validator.validator_for_uri()`) and then simply validate your
|
389
|
+
schema against it.
|
390
|
+
|
391
|
+
|
392
|
+
```ruby
|
393
|
+
require "json-schema"
|
394
|
+
|
395
|
+
schema = {
|
396
|
+
"type" => "object",
|
397
|
+
"properties" => {
|
398
|
+
"a" => {"type" => "integer"}
|
399
|
+
}
|
400
|
+
}
|
401
|
+
|
402
|
+
metaschema = JSON::Validator.validator_for_name("draft4").metaschema
|
403
|
+
# => true
|
404
|
+
JSON::Validator.validate(metaschema, schema)
|
405
|
+
```
|
406
|
+
|
407
|
+
Controlling Remote Schema Reading
|
408
|
+
---------------------------------
|
409
|
+
|
410
|
+
In some cases, you may wish to prevent the JSON Schema library from making HTTP
|
411
|
+
calls or reading local files in order to resolve `$ref` schemas. If you fully
|
412
|
+
control all schemas which should be used by validation, this could be
|
413
|
+
accomplished by registering all referenced schemas with the validator in
|
414
|
+
advance:
|
415
|
+
|
416
|
+
```ruby
|
417
|
+
schema = JSON::Schema.new(some_schema_definition, Addressable::URI.parse('http://example.com/my-schema'))
|
418
|
+
JSON::Validator.add_schema(schema)
|
419
|
+
```
|
420
|
+
|
421
|
+
If more extensive control is necessary, the `JSON::Schema::Reader` instance used
|
422
|
+
can be configured in a few ways:
|
423
|
+
|
424
|
+
```ruby
|
425
|
+
# Change the default schema reader used
|
426
|
+
JSON::Validator.schema_reader = JSON::Schema::Reader.new(:accept_uri => true, :accept_file => false)
|
427
|
+
|
428
|
+
# For this validation call, use a reader which only accepts URIs from my-website.com
|
429
|
+
schema_reader = JSON::Schema::Reader.new(
|
430
|
+
:accept_uri => proc { |uri| uri.host == 'my-website.com' }
|
431
|
+
)
|
432
|
+
JSON::Validator.validate(some_schema, some_object, :schema_reader => schema_reader)
|
433
|
+
```
|
434
|
+
|
435
|
+
The `JSON::Schema::Reader` interface requires only an object which responds to
|
436
|
+
`read(string)` and returns a `JSON::Schema` instance. See the [API
|
437
|
+
documentation](http://www.rubydoc.info/github/ruby-json-schema/json-schema/master/JSON/Schema/Reader)
|
438
|
+
for more information.
|
439
|
+
|
440
|
+
JSON Backends
|
441
|
+
-------------
|
442
|
+
|
443
|
+
The JSON Schema library currently supports the `json` and `yajl-ruby` backend
|
444
|
+
JSON parsers. If either of these libraries are installed, they will be
|
445
|
+
automatically loaded and used to parse any JSON strings supplied by the user.
|
446
|
+
|
447
|
+
If more than one of the supported JSON backends are installed, the `yajl-ruby`
|
448
|
+
parser is used by default. This can be changed by issuing the following before
|
449
|
+
validation:
|
450
|
+
|
451
|
+
```ruby
|
452
|
+
JSON::Validator.json_backend = :json
|
453
|
+
```
|
454
|
+
|
455
|
+
Optionally, the JSON Schema library supports using the MultiJSON library for
|
456
|
+
selecting JSON backends. If the MultiJSON library is installed, it will be
|
457
|
+
autoloaded.
|
458
|
+
|
459
|
+
Notes
|
460
|
+
-----
|
461
|
+
|
462
|
+
The 'format' attribute is only validated for the following values:
|
463
|
+
|
464
|
+
- date-time
|
465
|
+
- date
|
466
|
+
- time
|
467
|
+
- ip-address (IPv4 address in draft1, draft2 and draft3)
|
468
|
+
- ipv4 (IPv4 address in draft4)
|
469
|
+
- ipv6
|
470
|
+
- uri
|
471
|
+
|
472
|
+
All other 'format' attribute values are simply checked to ensure the instance
|
473
|
+
value is of the correct datatype (e.g., an instance value is validated to be an
|
474
|
+
integer or a float in the case of 'utc-millisec').
|
475
|
+
|
476
|
+
Additionally, JSON::Validator does not handle any json hyperschema attributes.
|
477
|
+
|
478
|
+
# Transfer Notice
|
479
|
+
|
480
|
+
This plugin was originally authored by [Iain Beeston](https://github.com/iainbeeston).
|
481
|
+
The maintainer preferred that [Vox Pupuli](https://voxpupuli.org/) take ownership of the module for future improvement and maintenance.
|
482
|
+
Existing pull requests and issues were transferred, please fork and continue to contribute [here](https://github.com/voxpupuli/json-schema).
|
483
|
+
|
484
|
+
# License
|
485
|
+
|
486
|
+
This gem is licensed unter the [MIT license](LICENSE.md).
|
487
|
+
|
488
|
+
## Release information
|
489
|
+
|
490
|
+
To make a new release, please do:
|
491
|
+
* update the version in VERSION.yml
|
492
|
+
* Install gems with `bundle install --with release --path .vendor`
|
493
|
+
* generate the changelog with `bundle exec rake changelog`
|
494
|
+
* Check if the new version matches the closed issues/PRs in the changelog
|
495
|
+
* Create a PR with it
|
496
|
+
* After it got merged, push a tag. GitHub actions will do the actual release to rubygems and GitHub Packages
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'json-schema/errors/validation_error'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class Attribute
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.build_fragment(fragments)
|
10
|
+
"#/#{fragments.join('/')}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.validation_error(processor, message, fragments, current_schema, failed_attribute, record_errors)
|
14
|
+
error = ValidationError.new(message, fragments, failed_attribute, current_schema)
|
15
|
+
if record_errors
|
16
|
+
processor.validation_error(error)
|
17
|
+
else
|
18
|
+
raise error
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.validation_errors(validator)
|
23
|
+
validator.validation_errors
|
24
|
+
end
|
25
|
+
|
26
|
+
TYPE_CLASS_MAPPINGS = {
|
27
|
+
"string" => String,
|
28
|
+
"number" => Numeric,
|
29
|
+
"integer" => Integer,
|
30
|
+
"boolean" => [TrueClass, FalseClass],
|
31
|
+
"object" => Hash,
|
32
|
+
"array" => Array,
|
33
|
+
"null" => NilClass,
|
34
|
+
"any" => Object
|
35
|
+
}
|
36
|
+
|
37
|
+
def self.data_valid_for_type?(data, type)
|
38
|
+
valid_classes = TYPE_CLASS_MAPPINGS.fetch(type) { return true }
|
39
|
+
Array(valid_classes).any? { |c| data.is_a?(c) }
|
40
|
+
end
|
41
|
+
|
42
|
+
# Lookup Schema type of given class instance
|
43
|
+
def self.type_of_data(data)
|
44
|
+
type, _ = TYPE_CLASS_MAPPINGS.map { |k,v| [k,v] }.sort_by { |(_, v)|
|
45
|
+
-Array(v).map { |klass| klass.ancestors.size }.max
|
46
|
+
}.find { |(_, v)|
|
47
|
+
Array(v).any? { |klass| data.kind_of?(klass) }
|
48
|
+
}
|
49
|
+
type
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.validate_on_false?
|
53
|
+
true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class AdditionalItemsAttribute < Attribute
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
+
return unless data.is_a?(Array)
|
8
|
+
|
9
|
+
schema = current_schema.schema
|
10
|
+
return unless schema['items'].is_a?(Array)
|
11
|
+
|
12
|
+
case schema['additionalItems']
|
13
|
+
when false
|
14
|
+
if schema['items'].length < data.length
|
15
|
+
message = "The property '#{build_fragment(fragments)}' contains additional array elements outside of the schema when none are allowed"
|
16
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
17
|
+
end
|
18
|
+
when Hash
|
19
|
+
additional_items_schema = JSON::Schema.new(schema['additionalItems'], current_schema.uri, validator)
|
20
|
+
data.each_with_index do |item, i|
|
21
|
+
next if i < schema['items'].length
|
22
|
+
additional_items_schema.validate(item, fragments + [i.to_s], processor, options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
require 'json-schema/attributes/extends'
|
3
|
+
|
4
|
+
module JSON
|
5
|
+
class Schema
|
6
|
+
class AdditionalPropertiesAttribute < Attribute
|
7
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
8
|
+
schema = current_schema.schema
|
9
|
+
return unless data.is_a?(Hash) && (schema['type'].nil? || schema['type'] == 'object')
|
10
|
+
|
11
|
+
extra_properties = remove_valid_properties(data.keys, current_schema, validator)
|
12
|
+
|
13
|
+
addprop = schema['additionalProperties']
|
14
|
+
if addprop.is_a?(Hash)
|
15
|
+
matching_properties = extra_properties # & addprop.keys
|
16
|
+
matching_properties.each do |key|
|
17
|
+
additional_property_schema = JSON::Schema.new(addprop, current_schema.uri, validator)
|
18
|
+
additional_property_schema.validate(data[key], fragments + [key], processor, options)
|
19
|
+
end
|
20
|
+
extra_properties -= matching_properties
|
21
|
+
end
|
22
|
+
|
23
|
+
if extra_properties.any? && (addprop == false || (addprop.is_a?(Hash) && !addprop.empty?))
|
24
|
+
message = "The property '#{build_fragment(fragments)}' contains additional properties #{extra_properties.inspect} outside of the schema when none are allowed"
|
25
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.remove_valid_properties(extra_properties, current_schema, validator)
|
30
|
+
schema = current_schema.schema
|
31
|
+
|
32
|
+
if schema['properties']
|
33
|
+
extra_properties = extra_properties - schema['properties'].keys
|
34
|
+
end
|
35
|
+
|
36
|
+
if schema['patternProperties']
|
37
|
+
schema['patternProperties'].each_key do |key|
|
38
|
+
regexp = Regexp.new(key)
|
39
|
+
extra_properties.reject! { |prop| regexp.match(prop) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
if extended_schemas = schema['extends']
|
44
|
+
extended_schemas = [extended_schemas] unless extended_schemas.is_a?(Array)
|
45
|
+
extended_schemas.each do |schema_value|
|
46
|
+
_, extended_schema = JSON::Schema::ExtendsAttribute.get_extended_uri_and_schema(schema_value, current_schema, validator)
|
47
|
+
if extended_schema
|
48
|
+
extra_properties = remove_valid_properties(extra_properties, extended_schema, validator)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
extra_properties
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|