json_schemer 1.0.3 → 2.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 +4 -4
- data/.github/workflows/ci.yml +7 -8
- data/CHANGELOG.md +96 -0
- data/Gemfile.lock +23 -14
- data/README.md +343 -20
- data/json_schemer.gemspec +8 -3
- data/lib/json_schemer/configuration.rb +31 -0
- data/lib/json_schemer/content.rb +18 -0
- data/lib/json_schemer/draft201909/meta.rb +320 -0
- data/lib/json_schemer/draft201909/vocab/applicator.rb +104 -0
- data/lib/json_schemer/draft201909/vocab/core.rb +45 -0
- data/lib/json_schemer/draft201909/vocab.rb +31 -0
- data/lib/json_schemer/draft202012/meta.rb +364 -0
- data/lib/json_schemer/draft202012/vocab/applicator.rb +382 -0
- data/lib/json_schemer/draft202012/vocab/content.rb +52 -0
- data/lib/json_schemer/draft202012/vocab/core.rb +160 -0
- data/lib/json_schemer/draft202012/vocab/format_annotation.rb +23 -0
- data/lib/json_schemer/draft202012/vocab/format_assertion.rb +23 -0
- data/lib/json_schemer/draft202012/vocab/meta_data.rb +30 -0
- data/lib/json_schemer/draft202012/vocab/unevaluated.rb +104 -0
- data/lib/json_schemer/draft202012/vocab/validation.rb +290 -0
- data/lib/json_schemer/draft202012/vocab.rb +105 -0
- data/lib/json_schemer/draft4/meta.rb +161 -0
- data/lib/json_schemer/draft4/vocab/validation.rb +38 -0
- data/lib/json_schemer/draft4/vocab.rb +18 -0
- data/lib/json_schemer/draft6/meta.rb +172 -0
- data/lib/json_schemer/draft6/vocab.rb +16 -0
- data/lib/json_schemer/draft7/meta.rb +183 -0
- data/lib/json_schemer/draft7/vocab/validation.rb +69 -0
- data/lib/json_schemer/draft7/vocab.rb +30 -0
- data/lib/json_schemer/errors.rb +1 -0
- data/lib/json_schemer/format/duration.rb +23 -0
- data/lib/json_schemer/format/json_pointer.rb +18 -0
- data/lib/json_schemer/format.rb +127 -106
- data/lib/json_schemer/keyword.rb +56 -0
- data/lib/json_schemer/location.rb +25 -0
- data/lib/json_schemer/openapi.rb +38 -0
- data/lib/json_schemer/openapi30/document.rb +1672 -0
- data/lib/json_schemer/openapi30/meta.rb +34 -0
- data/lib/json_schemer/openapi30/vocab/base.rb +18 -0
- data/lib/json_schemer/openapi30/vocab.rb +12 -0
- data/lib/json_schemer/openapi31/document.rb +1557 -0
- data/lib/json_schemer/openapi31/meta.rb +136 -0
- data/lib/json_schemer/openapi31/vocab/base.rb +127 -0
- data/lib/json_schemer/openapi31/vocab.rb +18 -0
- data/lib/json_schemer/output.rb +56 -0
- data/lib/json_schemer/resources.rb +24 -0
- data/lib/json_schemer/result.rb +242 -0
- data/lib/json_schemer/schema.rb +433 -0
- data/lib/json_schemer/version.rb +1 -1
- data/lib/json_schemer.rb +235 -32
- metadata +119 -18
- data/lib/json_schemer/schema/base.rb +0 -677
- data/lib/json_schemer/schema/draft4.json +0 -149
- data/lib/json_schemer/schema/draft4.rb +0 -44
- data/lib/json_schemer/schema/draft6.json +0 -155
- data/lib/json_schemer/schema/draft6.rb +0 -25
- data/lib/json_schemer/schema/draft7.json +0 -172
- data/lib/json_schemer/schema/draft7.rb +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04dbbf738ea9253437566fb50075ee7603fd0b536324181aebb0573c32c7f7bc
|
4
|
+
data.tar.gz: 29337d5892b33a2f74e435370986f059d7dd9762352bea610e7668dca3171e09
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 90f1510bcc40ad9500904453dee34434b91ef45b8ab7d8be84dc728aae4d4c1a4556037f1ae8b48595198529973fe2d1e5c20a64e5aeb9871cd6fddd23636268
|
7
|
+
data.tar.gz: c7e8a861d8f763d5248d79d486d8b253b9f81e40952e896d53b7dad84bdd5197a70224008e79de5cf5b6e7a3e9a8e646bd8af4188ae6a87c4a7ac9011998f36f
|
data/.github/workflows/ci.yml
CHANGED
@@ -6,22 +6,21 @@ jobs:
|
|
6
6
|
fail-fast: false
|
7
7
|
matrix:
|
8
8
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
9
|
-
ruby: [2.
|
9
|
+
ruby: [2.7, 3.0, 3.1, 3.2, 3.3, 3.4, head, jruby, jruby-head, truffleruby, truffleruby-head]
|
10
10
|
exclude:
|
11
|
+
- os: ubuntu-latest
|
12
|
+
ruby: head
|
13
|
+
- os: macos-latest
|
14
|
+
ruby: head
|
11
15
|
- os: windows-latest
|
12
16
|
ruby: truffleruby
|
13
17
|
- os: windows-latest
|
14
18
|
ruby: truffleruby-head
|
15
19
|
runs-on: ${{ matrix.os }}
|
16
20
|
steps:
|
17
|
-
- uses: actions/checkout@
|
21
|
+
- uses: actions/checkout@v4
|
18
22
|
- uses: ruby/setup-ruby@v1
|
19
23
|
with:
|
20
24
|
ruby-version: ${{ matrix.ruby }}
|
21
25
|
bundler-cache: true
|
22
|
-
- run:
|
23
|
-
mkdir -p tmp/gems
|
24
|
-
gem build json_schemer.gemspec
|
25
|
-
gem install --local --ignore-dependencies --no-document --install-dir tmp/gems json_schemer-*.gem
|
26
|
-
rm json_schemer-*.gem
|
27
|
-
bin/rake test
|
26
|
+
- run: bin/rake test
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,101 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [2.4.0] - 2025-02-01
|
4
|
+
|
5
|
+
### Bug Fixes
|
6
|
+
|
7
|
+
- Store schema resource file URIs as strings to prevent conflicts: https://github.com/davishmcclurg/json_schemer/pull/189
|
8
|
+
- Require OpenAPI `discriminator` instances to be objects: https://github.com/davishmcclurg/json_schemer/pull/206
|
9
|
+
- Pass configuration options to subschemas: https://github.com/davishmcclurg/json_schemer/pull/208
|
10
|
+
- Check applicable instance types in OpenAPI `format` extensions: https://github.com/davishmcclurg/json_schemer/pull/209
|
11
|
+
- Use correct max values for OpenAPI `int32`/`int64` formats: https://github.com/davishmcclurg/json_schemer/commit/386c2a6fe089350c61775716643ef0600898060e
|
12
|
+
|
13
|
+
[2.4.0]: https://github.com/davishmcclurg/json_schemer/releases/tag/v2.4.0
|
14
|
+
|
15
|
+
## [2.3.0] - 2024-05-30
|
16
|
+
|
17
|
+
### Ruby Versions
|
18
|
+
|
19
|
+
- Ruby 2.5 and 2.6 are no longer supported.
|
20
|
+
|
21
|
+
### Bug Fixes
|
22
|
+
|
23
|
+
- Remove `base64` runtime dependency: https://github.com/davishmcclurg/json_schemer/pull/182
|
24
|
+
- Relax `uuid` format validation: https://github.com/davishmcclurg/json_schemer/pull/183
|
25
|
+
|
26
|
+
[2.3.0]: https://github.com/davishmcclurg/json_schemer/releases/tag/v2.3.0
|
27
|
+
|
28
|
+
## [2.2.0] - 2024-03-02
|
29
|
+
|
30
|
+
### Bug Fixes
|
31
|
+
|
32
|
+
- Support symbol keys when accessing original instance: https://github.com/davishmcclurg/json_schemer/commit/d52c130e9967919c6cf1c9dbc3f0babfb8b01cf8
|
33
|
+
- Support custom keywords in nested schemas: https://github.com/davishmcclurg/json_schemer/commit/93c85a5006981347c7e9a4c11b73c6bdb65d8ba2
|
34
|
+
- Stringify instance location for custom keywords: https://github.com/davishmcclurg/json_schemer/commit/513c99130b9e7986b09881e7efd3fb7143744754
|
35
|
+
- Reduce unhelpful error output in `unevaluated` keywords: https://github.com/davishmcclurg/json_schemer/pull/164
|
36
|
+
- Handle parse errors during schema validation: https://github.com/davishmcclurg/json_schemer/pull/171
|
37
|
+
- Follow refs when finding default property values: https://github.com/davishmcclurg/json_schemer/pull/175
|
38
|
+
|
39
|
+
### Features
|
40
|
+
|
41
|
+
- Global configuration with `Configuration` object: https://github.com/davishmcclurg/json_schemer/pull/170
|
42
|
+
- Symbol key property defaults with `insert_property_defaults: :symbol`: https://github.com/davishmcclurg/json_schemer/commit/a72473dc84199107ddedc8998950e5b82273232a
|
43
|
+
- Consistent schema type support for schema validation methods: https://github.com/davishmcclurg/json_schemer/commit/bbcd0cea20cbaa61cf2bdae5f53840861cae54b8
|
44
|
+
- Validation option support for schema validation methods: https://github.com/davishmcclurg/json_schemer/commit/2eeef77de522f127619b7d0faa51e0d7e40977ad
|
45
|
+
|
46
|
+
[2.2.0]: https://github.com/davishmcclurg/json_schemer/releases/tag/v2.2.0
|
47
|
+
|
48
|
+
## [2.1.1] - 2023-11-28
|
49
|
+
|
50
|
+
### Bug Fixes
|
51
|
+
|
52
|
+
- Fix refs to/through keyword objects: https://github.com/davishmcclurg/json_schemer/pull/160
|
53
|
+
- Temporary fix for incorrect `uri-reference` format in OpenAPI 3.x: https://github.com/davishmcclurg/json_schemer/pull/161
|
54
|
+
|
55
|
+
[2.1.1]: https://github.com/davishmcclurg/json_schemer/releases/tag/v2.1.1
|
56
|
+
|
57
|
+
## [2.1.0] - 2023-11-17
|
58
|
+
|
59
|
+
### Bug Fixes
|
60
|
+
|
61
|
+
- Limit anyOf/oneOf discriminator to listed refs: https://github.com/davishmcclurg/json_schemer/pull/145
|
62
|
+
- Require discriminator `propertyName` property: https://github.com/davishmcclurg/json_schemer/pull/145
|
63
|
+
- Support `Schema#ref` in subschemas: https://github.com/davishmcclurg/json_schemer/pull/145
|
64
|
+
- Resolve JSON pointer refs using correct base URI: https://github.com/davishmcclurg/json_schemer/pull/147
|
65
|
+
- `date` format in OpenAPI 3.0: https://github.com/davishmcclurg/json_schemer/commit/69fe7a815ecf0cfb1c40ac402bf46a789c05e972
|
66
|
+
|
67
|
+
### Features
|
68
|
+
|
69
|
+
- Custom error messages with `x-error` keyword and I18n: https://github.com/davishmcclurg/json_schemer/pull/149
|
70
|
+
- Custom content encodings and media types: https://github.com/davishmcclurg/json_schemer/pull/148
|
71
|
+
|
72
|
+
[2.1.0]: https://github.com/davishmcclurg/json_schemer/releases/tag/v2.1.0
|
73
|
+
|
74
|
+
## [2.0.0] - 2023-08-20
|
75
|
+
|
76
|
+
For 2.0.0, much of the codebase was rewritten to simplify support for the two new JSON Schema draft versions (2019-09 and 2020-12). The major change is moving each keyword into its own class and organizing them into vocabularies. [Output formats](https://json-schema.org/draft/2020-12/json-schema-core.html#section-12) and [annotations](https://json-schema.org/draft/2020-12/json-schema-core.html#section-7.7) from the new drafts are also supported. The known breaking changes are listed below, but there may be others that haven't been identified.
|
77
|
+
|
78
|
+
### Breaking Changes
|
79
|
+
|
80
|
+
- The default meta schema is now Draft 2020-12. Other meta schemas can be specified using `meta_schema`.
|
81
|
+
- Schemas use `json-schemer://schema` as the default base URI. Relative `$id` and `$ref` values are joined to the default base URI and are always absolute. For example, the schema `{ '$id' => 'foo', '$ref' => 'bar' }` uses `json-schemer://schema/foo` as the base URI and passes `json-schemer://schema/bar` to the ref resolver. For relative refs, `URI#path` can be used in the ref resolver to access the relative portion, ie: `URI('json-schemer://schema/bar').path => "/bar"`.
|
82
|
+
- Property validation hooks (`before_property_validation` and `after_property_validation`) run immediately before and after `properties` validation. Previously, `before_property_validation` ran before all "object" validations (`dependencies`, `patternProperties`, `additionalProperties`, etc) and `after_property_validation` was called after them.
|
83
|
+
- `insert_property_defaults` now inserts defaults in conditional subschemas when possible (if there's only one default or if there's only one unique default from a valid subtree).
|
84
|
+
- Error output
|
85
|
+
- Special characters in `schema_pointer` are no longer percent encoded (eg, `definitions/foo\"bar` instead of `/definitions/foo%22bar`)
|
86
|
+
- Keyword validation order changed so errors may be returned in a different order (eg, `items` errors before `contains`).
|
87
|
+
- Array `dependencies` return `"type": "dependencies"` errors instead of `"required"` and point to the schema that contains the `dependencies` keyword.
|
88
|
+
- `not` errors point to the schema that contains the `not` keyword (instead of the schema defined by the `not` keyword).
|
89
|
+
- Custom keyword errors are now always wrapped in regular error hashes. Returned strings are used to set `type`:
|
90
|
+
```
|
91
|
+
>> JSONSchemer.schema({ 'x' => 'y' }, :keywords => { 'x' => proc { false } }).validate({}).to_a
|
92
|
+
=> [{"data"=>{}, "data_pointer"=>"", "schema"=>{"x"=>"y"}, "schema_pointer"=>"", "root_schema"=>{"x"=>"y"}, "type"=>"x"}]
|
93
|
+
>> JSONSchemer.schema({ 'x' => 'y' }, :keywords => { 'x' => proc { 'wrong!' } }).validate({}).to_a
|
94
|
+
=> [{"data"=>{}, "data_pointer"=>"", "schema"=>{"x"=>"y"}, "schema_pointer"=>"", "root_schema"=>{"x"=>"y"}, "type"=>"wrong!"}]
|
95
|
+
```
|
96
|
+
|
97
|
+
[2.0.0]: https://github.com/davishmcclurg/json_schemer/releases/tag/v2.0.0
|
98
|
+
|
3
99
|
## [1.0.0] - 2023-05-26
|
4
100
|
|
5
101
|
### Breaking Changes
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
json_schemer (
|
4
|
+
json_schemer (2.4.0)
|
5
|
+
bigdecimal
|
5
6
|
hana (~> 1.3)
|
6
7
|
regexp_parser (~> 2.0)
|
7
8
|
simpleidn (~> 0.2)
|
@@ -9,34 +10,42 @@ PATH
|
|
9
10
|
GEM
|
10
11
|
remote: https://rubygems.org/
|
11
12
|
specs:
|
12
|
-
|
13
|
+
base64 (0.2.0)
|
14
|
+
bigdecimal (3.1.9)
|
15
|
+
bigdecimal (3.1.9-java)
|
16
|
+
concurrent-ruby (1.3.5)
|
17
|
+
csv (3.3.2)
|
18
|
+
docile (1.4.1)
|
13
19
|
hana (1.3.7)
|
14
|
-
|
15
|
-
|
16
|
-
|
20
|
+
i18n (1.14.6)
|
21
|
+
concurrent-ruby (~> 1.0)
|
22
|
+
i18n-debug (1.2.0)
|
23
|
+
i18n (< 2)
|
24
|
+
minitest (5.25.4)
|
25
|
+
rake (13.2.1)
|
26
|
+
regexp_parser (2.10.0)
|
17
27
|
simplecov (0.22.0)
|
18
28
|
docile (~> 1.1)
|
19
29
|
simplecov-html (~> 0.11)
|
20
30
|
simplecov_json_formatter (~> 0.1)
|
21
|
-
simplecov-html (0.
|
31
|
+
simplecov-html (0.13.1)
|
22
32
|
simplecov_json_formatter (0.1.4)
|
23
|
-
simpleidn (0.2.
|
24
|
-
unf (~> 0.1.4)
|
25
|
-
unf (0.1.4)
|
26
|
-
unf_ext
|
27
|
-
unf (0.1.4-java)
|
28
|
-
unf_ext (0.0.8.2)
|
33
|
+
simpleidn (0.2.3)
|
29
34
|
|
30
35
|
PLATFORMS
|
31
36
|
java
|
32
37
|
ruby
|
33
38
|
|
34
39
|
DEPENDENCIES
|
35
|
-
|
40
|
+
base64
|
41
|
+
bundler (~> 2.4.0)
|
42
|
+
csv
|
43
|
+
i18n
|
44
|
+
i18n-debug
|
36
45
|
json_schemer!
|
37
46
|
minitest (~> 5.0)
|
38
47
|
rake (~> 13.0)
|
39
48
|
simplecov (~> 0.22)
|
40
49
|
|
41
50
|
BUNDLED WITH
|
42
|
-
2.
|
51
|
+
2.4.22
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# JSONSchemer
|
2
2
|
|
3
|
-
JSON Schema validator. Supports drafts 4, 6, and
|
3
|
+
JSON Schema validator. Supports drafts 4, 6, 7, 2019-09, 2020-12, OpenAPI 3.0, and OpenAPI 3.1.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -50,7 +50,8 @@ schemer.validate({ 'abc' => 10 }).to_a
|
|
50
50
|
# "schema"=>{"type"=>"integer", "minimum"=>11},
|
51
51
|
# "schema_pointer"=>"/properties/abc",
|
52
52
|
# "root_schema"=>{"type"=>"object", "properties"=>{"abc"=>{"type"=>"integer", "minimum"=>11}}},
|
53
|
-
# "type"=>"minimum"
|
53
|
+
# "type"=>"minimum",
|
54
|
+
# "error"=>"number at `/abc` is less than: 11"}]
|
54
55
|
|
55
56
|
# default property values
|
56
57
|
|
@@ -82,27 +83,65 @@ schemer = JSONSchemer.schema(schema)
|
|
82
83
|
|
83
84
|
# schema validation
|
84
85
|
|
85
|
-
JSONSchemer.valid_schema?({ '$id' => '
|
86
|
+
JSONSchemer.valid_schema?({ '$id' => 'valid' })
|
86
87
|
# => true
|
87
88
|
|
88
|
-
JSONSchemer.validate_schema({ '$id' =>
|
89
|
-
# => [{"data"=>
|
89
|
+
JSONSchemer.validate_schema({ '$id' => '#invalid' }).to_a
|
90
|
+
# => [{"data"=>"#invalid",
|
90
91
|
# "data_pointer"=>"/$id",
|
91
|
-
# "schema"=>{"
|
92
|
+
# "schema"=>{"$ref"=>"#/$defs/uriReferenceString", "$comment"=>"Non-empty fragments not allowed.", "pattern"=>"^[^#]*#?$"},
|
92
93
|
# "schema_pointer"=>"/properties/$id",
|
93
94
|
# "root_schema"=>{...meta schema},
|
94
|
-
# "type"=>"
|
95
|
+
# "type"=>"pattern",
|
96
|
+
# "error"=>"string at `/$id` does not match pattern: ^[^#]*#?$"}]
|
95
97
|
|
96
|
-
|
97
|
-
# => true
|
98
|
+
# subschemas
|
98
99
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
100
|
+
schema = {
|
101
|
+
'type' => 'integer',
|
102
|
+
'$defs' => {
|
103
|
+
'foo' => {
|
104
|
+
'type' => 'string'
|
105
|
+
}
|
106
|
+
}
|
107
|
+
}
|
108
|
+
schemer = JSONSchemer.schema(schema)
|
109
|
+
|
110
|
+
schemer.ref('#/$defs/foo').validate(1).to_a
|
111
|
+
# => [{"data"=>1,
|
112
|
+
# "data_pointer"=>"",
|
113
|
+
# "schema"=>{"type"=>"string"},
|
114
|
+
# "schema_pointer"=>"/$defs/foo",
|
115
|
+
# "root_schema"=>{"type"=>"integer", "$defs"=>{"foo"=>{"type"=>"string"}}},
|
116
|
+
# "type"=>"string",
|
117
|
+
# "error"=>"value at root is not a string"}]
|
118
|
+
|
119
|
+
# schema bundling (https://json-schema.org/draft/2020-12/json-schema-core.html#section-9.3)
|
120
|
+
|
121
|
+
schema = {
|
122
|
+
'$id' => 'http://example.com/schema',
|
123
|
+
'allOf' => [
|
124
|
+
{ '$ref' => 'schema/one' },
|
125
|
+
{ '$ref' => 'schema/two' }
|
126
|
+
]
|
127
|
+
}
|
128
|
+
refs = {
|
129
|
+
URI('http://example.com/schema/one') => {
|
130
|
+
'type' => 'integer'
|
131
|
+
},
|
132
|
+
URI('http://example.com/schema/two') => {
|
133
|
+
'minimum' => 11
|
134
|
+
}
|
135
|
+
}
|
136
|
+
schemer = JSONSchemer.schema(schema, :ref_resolver => refs.to_proc)
|
137
|
+
|
138
|
+
schemer.bundle
|
139
|
+
# => {"$id"=>"http://example.com/schema",
|
140
|
+
# "allOf"=>[{"$ref"=>"schema/one"}, {"$ref"=>"schema/two"}],
|
141
|
+
# "$schema"=>"https://json-schema.org/draft/2020-12/schema",
|
142
|
+
# "$defs"=>
|
143
|
+
# {"http://example.com/schema/one"=>{"type"=>"integer", "$id"=>"http://example.com/schema/one", "$schema"=>"https://json-schema.org/draft/2020-12/schema"},
|
144
|
+
# "http://example.com/schema/two"=>{"minimum"=>11, "$id"=>"http://example.com/schema/two", "$schema"=>"https://json-schema.org/draft/2020-12/schema"}}}
|
106
145
|
```
|
107
146
|
|
108
147
|
## Options
|
@@ -111,13 +150,58 @@ JSONSchemer.schema({ '$id' => nil }).validate_schema.to_a
|
|
111
150
|
JSONSchemer.schema(
|
112
151
|
schema,
|
113
152
|
|
114
|
-
#
|
153
|
+
# meta schema to use for vocabularies (keyword behavior) and schema validation
|
154
|
+
# String/JSONSchemer::Schema
|
155
|
+
# 'https://json-schema.org/draft/2020-12/schema': JSONSchemer.draft202012
|
156
|
+
# 'https://json-schema.org/draft/2019-09/schema': JSONSchemer.draft201909
|
157
|
+
# 'http://json-schema.org/draft-07/schema#': JSONSchemer.draft7
|
158
|
+
# 'http://json-schema.org/draft-06/schema#': JSONSchemer.draft6
|
159
|
+
# 'http://json-schema.org/draft-04/schema#': JSONSchemer.draft4
|
160
|
+
# 'http://json-schema.org/schema#': JSONSchemer.draft4
|
161
|
+
# 'https://spec.openapis.org/oas/3.1/dialect/base': JSONSchemer.openapi31
|
162
|
+
# 'json-schemer://openapi30/schema': JSONSchemer.openapi30
|
163
|
+
# default: JSONSchemer.draft202012
|
164
|
+
meta_schema: 'https://json-schema.org/draft/2020-12/schema',
|
165
|
+
|
166
|
+
# validate `format` (https://json-schema.org/draft/2020-12/json-schema-validation.html#section-7)
|
115
167
|
# true/false
|
116
168
|
# default: true
|
117
169
|
format: true,
|
118
170
|
|
171
|
+
# custom formats
|
172
|
+
formats: {
|
173
|
+
'int32' => proc do |instance, _format|
|
174
|
+
instance.is_a?(Integer) && instance.bit_length <= 32
|
175
|
+
end,
|
176
|
+
# disable specific format
|
177
|
+
'email' => false
|
178
|
+
},
|
179
|
+
|
180
|
+
# custom content encodings
|
181
|
+
# only `base64` is available by default
|
182
|
+
content_encodings: {
|
183
|
+
# return [success, annotation] tuple
|
184
|
+
'urlsafe_base64' => proc do |instance|
|
185
|
+
[true, Base64.urlsafe_decode64(instance)]
|
186
|
+
rescue
|
187
|
+
[false, nil]
|
188
|
+
end
|
189
|
+
},
|
190
|
+
|
191
|
+
# custom content media types
|
192
|
+
# only `application/json` is available by default
|
193
|
+
content_media_types: {
|
194
|
+
# return [success, annotation] tuple
|
195
|
+
'text/csv' => proc do |instance|
|
196
|
+
[true, CSV.parse(instance)]
|
197
|
+
rescue
|
198
|
+
[false, nil]
|
199
|
+
end
|
200
|
+
},
|
201
|
+
|
119
202
|
# insert default property values during validation
|
120
|
-
#
|
203
|
+
# string keys by default (use `:symbol` to insert symbol keys)
|
204
|
+
# true/false/:symbol
|
121
205
|
# default: false
|
122
206
|
insert_property_defaults: true,
|
123
207
|
|
@@ -147,10 +231,243 @@ JSONSchemer.schema(
|
|
147
231
|
# default: 'ruby'
|
148
232
|
regexp_resolver: proc do |pattern|
|
149
233
|
RE2::Regexp.new(pattern)
|
150
|
-
end
|
234
|
+
end,
|
235
|
+
|
236
|
+
# output formatting (https://json-schema.org/draft/2020-12/json-schema-core.html#section-12)
|
237
|
+
# 'classic'/'flag'/'basic'/'detailed'/'verbose'
|
238
|
+
# default: 'classic'
|
239
|
+
output_format: 'basic',
|
240
|
+
|
241
|
+
# validate `readOnly`/`writeOnly` keywords (https://spec.openapis.org/oas/v3.0.3#fixed-fields-19)
|
242
|
+
# 'read'/'write'/nil
|
243
|
+
# default: nil
|
244
|
+
access_mode: 'read'
|
151
245
|
)
|
152
246
|
```
|
153
247
|
|
248
|
+
## Global Configuration
|
249
|
+
|
250
|
+
Configuration options can be set globally by modifying `JSONSchemer.configuration`. Global options are applied to any new schemas at creation time (global configuration changes are not reflected in existing schemas). They can be overridden with the regular keyword arguments described [above](#options).
|
251
|
+
|
252
|
+
```ruby
|
253
|
+
# configuration block
|
254
|
+
JSONSchemer.configure do |config|
|
255
|
+
config.regexp_resolver = 'ecma'
|
256
|
+
end
|
257
|
+
|
258
|
+
# configuration accessors
|
259
|
+
JSONSchemer.configuration.insert_property_defaults = true
|
260
|
+
```
|
261
|
+
|
262
|
+
## Custom Error Messages
|
263
|
+
|
264
|
+
Error messages can be customized using the `x-error` keyword and/or [I18n](https://github.com/ruby-i18n/i18n) translations. `x-error` takes precedence if both are defined.
|
265
|
+
|
266
|
+
### `x-error` Keyword
|
267
|
+
|
268
|
+
```ruby
|
269
|
+
# override all errors for a schema
|
270
|
+
schemer = JSONSchemer.schema({
|
271
|
+
'type' => 'string',
|
272
|
+
'x-error' => 'custom error for schema and all keywords'
|
273
|
+
})
|
274
|
+
|
275
|
+
schemer.validate(1).first
|
276
|
+
# => {"data"=>1,
|
277
|
+
# "data_pointer"=>"",
|
278
|
+
# "schema"=>{"type"=>"string", "x-error"=>"custom error for schema and all keywords"},
|
279
|
+
# "schema_pointer"=>"",
|
280
|
+
# "root_schema"=>{"type"=>"string", "x-error"=>"custom error for schema and all keywords"},
|
281
|
+
# "type"=>"string",
|
282
|
+
# "error"=>"custom error for schema and all keywords",
|
283
|
+
# "x-error"=>true}
|
284
|
+
|
285
|
+
schemer.validate(1, :output_format => 'basic')
|
286
|
+
# => {"valid"=>false,
|
287
|
+
# "keywordLocation"=>"",
|
288
|
+
# "absoluteKeywordLocation"=>"json-schemer://schema#",
|
289
|
+
# "instanceLocation"=>"",
|
290
|
+
# "error"=>"custom error for schema and all keywords",
|
291
|
+
# "x-error"=>true,
|
292
|
+
# "errors"=>#<Enumerator: ...>}
|
293
|
+
|
294
|
+
# keyword-specific errors
|
295
|
+
schemer = JSONSchemer.schema({
|
296
|
+
'type' => 'string',
|
297
|
+
'minLength' => 10,
|
298
|
+
'x-error' => {
|
299
|
+
'type' => 'custom error for `type` keyword',
|
300
|
+
# special `^` keyword for schema-level error
|
301
|
+
'^' => 'custom error for schema',
|
302
|
+
# same behavior as when `x-error` is a string
|
303
|
+
'*' => 'fallback error for schema and all keywords'
|
304
|
+
}
|
305
|
+
})
|
306
|
+
|
307
|
+
schemer.validate(1).map { _1.fetch('error') }
|
308
|
+
# => ["custom error for `type` keyword"]
|
309
|
+
|
310
|
+
schemer.validate('1').map { _1.fetch('error') }
|
311
|
+
# => ["custom error for schema and all keywords"]
|
312
|
+
|
313
|
+
schemer.validate(1, :output_format => 'basic').fetch('error')
|
314
|
+
# => "custom error for schema"
|
315
|
+
|
316
|
+
# variable interpolation (instance/instanceLocation/keywordLocation/absoluteKeywordLocation)
|
317
|
+
schemer = JSONSchemer.schema({
|
318
|
+
'$id' => 'https://example.com/schema',
|
319
|
+
'properties' => {
|
320
|
+
'abc' => {
|
321
|
+
'type' => 'string',
|
322
|
+
'x-error' => <<~ERROR
|
323
|
+
instance: %{instance}
|
324
|
+
instance location: %{instanceLocation}
|
325
|
+
keyword location: %{keywordLocation}
|
326
|
+
absolute keyword location: %{absoluteKeywordLocation}
|
327
|
+
ERROR
|
328
|
+
}
|
329
|
+
}
|
330
|
+
})
|
331
|
+
|
332
|
+
puts schemer.validate({ 'abc' => 1 }).first.fetch('error')
|
333
|
+
# instance: 1
|
334
|
+
# instance location: /abc
|
335
|
+
# keyword location: /properties/abc/type
|
336
|
+
# absolute keyword location: https://example.com/schema#/properties/abc/type
|
337
|
+
```
|
338
|
+
|
339
|
+
### I18n
|
340
|
+
|
341
|
+
When the [I18n gem](https://github.com/ruby-i18n/i18n) is loaded, custom error messages are looked up under the `json_schemer` key. It may be necessary to restart your application after adding the root key because the existence check is cached for performance reasons.
|
342
|
+
|
343
|
+
Translation keys are looked up in this order:
|
344
|
+
|
345
|
+
1. `$LOCALE.json_schemer.errors.$ABSOLUTE_KEYWORD_LOCATION`
|
346
|
+
2. `$LOCALE.json_schemer.errors.$SCHEMA_ID.$KEYWORD_LOCATION`
|
347
|
+
3. `$LOCALE.json_schemer.errors.$KEYWORD_LOCATION`
|
348
|
+
4. `$LOCALE.json_schemer.errors.$SCHEMA_ID.$KEYWORD`
|
349
|
+
5. `$LOCALE.json_schemer.errors.$SCHEMA_ID.*`
|
350
|
+
6. `$LOCALE.json_schemer.errors.$META_SCHEMA_ID.$KEYWORD`
|
351
|
+
7. `$LOCALE.json_schemer.errors.$META_SCHEMA_ID.*`
|
352
|
+
8. `$LOCALE.json_schemer.errors.$KEYWORD`
|
353
|
+
9. `$LOCALE.json_schemer.errors.*`
|
354
|
+
|
355
|
+
Example translations file:
|
356
|
+
|
357
|
+
```yaml
|
358
|
+
en:
|
359
|
+
json_schemer:
|
360
|
+
errors:
|
361
|
+
'https://example.com/schema#/properties/abc/type': custom error for absolute keyword location
|
362
|
+
'https://example.com/schema':
|
363
|
+
'#/properties/abc/type': custom error for keyword location, nested under schema $id
|
364
|
+
'type': custom error for `type` keyword, nested under schema $id
|
365
|
+
'^': custom error for schema, nested under schema $id
|
366
|
+
'*': fallback error for schema and all keywords, nested under schema $id
|
367
|
+
'#/properties/abc/type': custom error for keyword location
|
368
|
+
'http://json-schema.org/draft-07/schema#':
|
369
|
+
'type': custom error for `type` keyword, nested under meta-schema $id ($schema)
|
370
|
+
'^': custom error for schema, nested under meta-schema $id
|
371
|
+
'*': fallback error for schema and all keywords, nested under meta-schema $id ($schema)
|
372
|
+
'type': custom error for `type` keyword
|
373
|
+
'^': custom error for schema
|
374
|
+
# variable interpolation (instance/instanceLocation/keywordLocation/absoluteKeywordLocation)
|
375
|
+
'*': |
|
376
|
+
fallback error for schema and all keywords
|
377
|
+
instance: %{instance}
|
378
|
+
instance location: %{instanceLocation}
|
379
|
+
keyword location: %{keywordLocation}
|
380
|
+
absolute keyword location: %{absoluteKeywordLocation}
|
381
|
+
```
|
382
|
+
|
383
|
+
And output:
|
384
|
+
|
385
|
+
```ruby
|
386
|
+
require 'i18n'
|
387
|
+
I18n.locale = :en # $LOCALE=en
|
388
|
+
|
389
|
+
schemer = JSONSchemer.schema({
|
390
|
+
'$id' => 'https://example.com/schema', # $SCHEMA_ID=https://example.com/schema
|
391
|
+
'$schema' => 'http://json-schema.org/draft-07/schema#', # $META_SCHEMA_ID=http://json-schema.org/draft-07/schema#
|
392
|
+
'properties' => {
|
393
|
+
'abc' => {
|
394
|
+
'type' => 'integer' # $KEYWORD=type
|
395
|
+
} # $KEYWORD_LOCATION=#/properties/abc/type
|
396
|
+
} # $ABSOLUTE_KEYWORD_LOCATION=https://example.com/schema#/properties/abc/type
|
397
|
+
})
|
398
|
+
|
399
|
+
schemer.validate({ 'abc' => 'not-an-integer' }).first
|
400
|
+
# => {"data"=>"not-an-integer",
|
401
|
+
# "data_pointer"=>"/abc",
|
402
|
+
# "schema"=>{"type"=>"integer"},
|
403
|
+
# "schema_pointer"=>"/properties/abc",
|
404
|
+
# "root_schema"=>{"$id"=>"https://example.com/schema", "$schema"=>"http://json-schema.org/draft-07/schema#", "properties"=>{"abc"=>{"type"=>"integer"}}},
|
405
|
+
# "type"=>"integer",
|
406
|
+
# "error"=>"custom error for absolute keyword location",
|
407
|
+
# "i18n"=>true
|
408
|
+
```
|
409
|
+
|
410
|
+
In the example above, custom error messsages are looked up using the following keys (in order until one is found):
|
411
|
+
|
412
|
+
1. `en.json_schemer.errors.'https://example.com/schema#/properties/abc/type'`
|
413
|
+
2. `en.json_schemer.errors.'https://example.com/schema'.'#/properties/abc/type'`
|
414
|
+
3. `en.json_schemer.errors.'#/properties/abc/type'`
|
415
|
+
4. `en.json_schemer.errors.'https://example.com/schema'.type`
|
416
|
+
5. `en.json_schemer.errors.'https://example.com/schema'.*`
|
417
|
+
6. `en.json_schemer.errors.'http://json-schema.org/draft-07/schema#'.type`
|
418
|
+
7. `en.json_schemer.errors.'http://json-schema.org/draft-07/schema#'.*`
|
419
|
+
8. `en.json_schemer.errors.type`
|
420
|
+
9. `en.json_schemer.errors.*`
|
421
|
+
|
422
|
+
## OpenAPI
|
423
|
+
|
424
|
+
```ruby
|
425
|
+
document = JSONSchemer.openapi({
|
426
|
+
'openapi' => '3.1.0',
|
427
|
+
'info' => {
|
428
|
+
'title' => 'example'
|
429
|
+
},
|
430
|
+
'components' => {
|
431
|
+
'schemas' => {
|
432
|
+
'example' => {
|
433
|
+
'type' => 'integer'
|
434
|
+
}
|
435
|
+
}
|
436
|
+
}
|
437
|
+
})
|
438
|
+
|
439
|
+
# document validation using meta schema
|
440
|
+
|
441
|
+
document.valid?
|
442
|
+
# => false
|
443
|
+
|
444
|
+
document.validate.to_a
|
445
|
+
# => [{"data"=>{"title"=>"example"},
|
446
|
+
# "data_pointer"=>"/info",
|
447
|
+
# "schema"=>{...info schema},
|
448
|
+
# "schema_pointer"=>"/$defs/info",
|
449
|
+
# "root_schema"=>{...meta schema},
|
450
|
+
# "type"=>"required",
|
451
|
+
# "details"=>{"missing_keys"=>["version"]}},
|
452
|
+
# ...]
|
453
|
+
|
454
|
+
# data validation using schema by name (in `components/schemas`)
|
455
|
+
|
456
|
+
document.schema('example').valid?(1)
|
457
|
+
# => true
|
458
|
+
|
459
|
+
document.schema('example').valid?('one')
|
460
|
+
# => false
|
461
|
+
|
462
|
+
# data validation using schema by ref
|
463
|
+
|
464
|
+
document.ref('#/components/schemas/example').valid?(1)
|
465
|
+
# => true
|
466
|
+
|
467
|
+
document.ref('#/components/schemas/example').valid?('one')
|
468
|
+
# => false
|
469
|
+
```
|
470
|
+
|
154
471
|
## CLI
|
155
472
|
|
156
473
|
The `json_schemer` executable takes a JSON schema file as the first argument followed by one or more JSON data files to validate. If there are any validation errors, it outputs them and returns an error code.
|
@@ -181,7 +498,13 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
181
498
|
|
182
499
|
## Build Status
|
183
500
|
|
184
|
-

|
502
|
+
<br>
|
503
|
+

|
504
|
+

|
505
|
+

|
506
|
+

|
507
|
+

|
185
508
|
|
186
509
|
## Contributing
|
187
510
|
|
data/json_schemer.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["David Harsha"]
|
10
10
|
spec.email = ["davishmcclurg@gmail.com"]
|
11
11
|
|
12
|
-
spec.summary = "JSON Schema validator. Supports drafts 4, 6, and
|
12
|
+
spec.summary = "JSON Schema validator. Supports drafts 4, 6, 7, 2019-09, 2020-12, OpenAPI 3.0, and OpenAPI 3.1."
|
13
13
|
spec.homepage = "https://github.com/davishmcclurg/json_schemer"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
@@ -20,13 +20,18 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
21
|
spec.require_paths = ["lib"]
|
22
22
|
|
23
|
-
spec.required_ruby_version = '>= 2.
|
23
|
+
spec.required_ruby_version = '>= 2.7'
|
24
24
|
|
25
|
-
spec.add_development_dependency "
|
25
|
+
spec.add_development_dependency "base64"
|
26
|
+
spec.add_development_dependency "bundler", "~> 2.4.0"
|
26
27
|
spec.add_development_dependency "rake", "~> 13.0"
|
27
28
|
spec.add_development_dependency "minitest", "~> 5.0"
|
28
29
|
spec.add_development_dependency "simplecov", "~> 0.22"
|
30
|
+
spec.add_development_dependency "csv"
|
31
|
+
spec.add_development_dependency "i18n"
|
32
|
+
spec.add_development_dependency "i18n-debug"
|
29
33
|
|
34
|
+
spec.add_runtime_dependency "bigdecimal"
|
30
35
|
spec.add_runtime_dependency "hana", "~> 1.3"
|
31
36
|
spec.add_runtime_dependency "regexp_parser", "~> 2.0"
|
32
37
|
spec.add_runtime_dependency "simpleidn", "~> 0.2"
|