npm 中文文档 npm 中文文档
指南
npmjs.com (opens new window)
指南
npmjs.com (opens new window)
  • 快速入门

    • npm 是什么?
    • npm 安装和更新
    • npm 防止权限错误
    • npm package.json 文件
    • npm 安装包
    • npm 更新包
    • npm 卸载包
    • npm 创建 Node.js 模块
    • npm 发布和更新包
    • npm 使用语义化版本
    • npm 使用 Dist-tags 标记包
    • npm 包和模块的了解
  • 命令行
  • 配置 npm

Ruby JSON Schema Validator


Test Release

This library is intended to provide Ruby with an interface for validating JSON objects against a JSON schema conforming to JSON Schema Draft6. Legacy support for JSON Schema Draft 4, JSON Schema Draft 3, JSON Schema Draft 2, and JSON Schema Draft 1 is also included.

Additional Resources


Google Groups
#voxpupuli on irc.libera.chat

Version 2.0.0 Upgrade Notes


Please be aware that the upgrade to version 2.0.0 will use Draft-04 by default, so schemas that do not declare a validator using the $schema keyword will use Draft-04 now instead of Draft-03. This is the reason for the major version upgrade.

Version 3.0.0 Upgrade Notes


All individual changes are documented in the CHANGELOG.md. The biggest change is that the new version only supports Ruby 2.5 and newer. Take a look into the gemspec file to see the currently supported Ruby version and also .github/workflows/test.yml to see the Ruby versions we test on.

Installation


From rubygems.org:

  1. ``` shell
  2. gem install json-schema
  3. ```

From the git repo:

  1. ``` shell
  2. gem build json-schema.gemspec
  3. gem install json-schema-*.gem
  4. ```

Validation


Three base validation methods exist:

validate : returns a boolean on whether a validation attempt passes
validate! : throws a JSON::Schema::ValidationError with an appropriate message/trace on where the validation failed
fully_validate : builds an array of validation errors return when validation is complete

All methods take two arguments, which can be either a JSON string, a file containing JSON, or a Ruby object representing JSON data. The first argument to these methods is always the schema, the second is always the data to validate. An optional third options argument is also accepted; available options are used in the examples below.

By default, the validator uses the JSON Schema Draft4 specification for validation; however, the user is free to specify additional specifications or extend existing ones. Legacy support for Draft 1, Draft 2, and Draft 3 is included by either passing an optional :version parameter to the validate method (set either as :draft1 or draft2 ), or by declaring the $schema attribute in the schema and referencing the appropriate specification URI. Note that the $schema attribute takes precedence over the :version option during parsing and validation.

For further information on json schema itself refer to UnderstandingJSON Schema.

Basic Usage


  1. ``` ruby
  2. require "json-schema"

  3. schema = {
  4.   "type" => "object",
  5.   "required" => ["a"],
  6.   "properties" => {
  7.     "a" => {"type" => "integer"}
  8.   }
  9. }

  10. #
  11. # validate ruby objects against a ruby schema
  12. #

  13. # => true
  14. JSON::Validator.validate(schema, { "a" => 5 })
  15. # => false
  16. JSON::Validator.validate(schema, {})

  17. #
  18. # validate a json string against a json schema file
  19. #

  20. require "json"
  21. File.write("schema.json", JSON.dump(schema))

  22. # => true
  23. JSON::Validator.validate('schema.json', '{ "a": 5 }')

  24. #
  25. # raise an error when validation fails
  26. #

  27. # => "The property '#/a' of type String did not match the following type: integer"
  28. begin
  29.   JSON::Validator.validate!(schema, { "a" => "taco" })
  30. rescue JSON::Schema::ValidationError => e
  31.   e.message
  32. end

  33. #
  34. # return an array of error messages when validation fails
  35. #

  36. # => ["The property '#/a' of type String did not match the following type: integer in schema 18a1ffbb-4681-5b00-bd15-2c76aee4b28f"]
  37. JSON::Validator.fully_validate(schema, { "a" => "taco" })
  38. ```

Advanced Options


  1. ``` ruby
  2. require "json-schema"

  3. schema = {
  4.   "type"=>"object",
  5.   "required" => ["a"],
  6.   "properties" => {
  7.     "a" => {
  8.       "type" => "integer",
  9.       "default" => 42
  10.     },
  11.     "b" => {
  12.       "type" => "object",
  13.       "properties" => {
  14.         "x" => {
  15.           "type" => "integer"
  16.         }
  17.       }
  18.     }
  19.   }
  20. }

  21. #
  22. # with the `:list` option, a list can be validated against a schema that represents the individual objects
  23. #

  24. # => true
  25. JSON::Validator.validate(schema, [{"a" => 1}, {"a" => 2}, {"a" => 3}], :list => true)
  26. # => false
  27. JSON::Validator.validate(schema, [{"a" => 1}, {"a" => 2}, {"a" => 3}])

  28. #
  29. # with the `:errors_as_objects` option, `#fully_validate` returns errors as hashes instead of strings
  30. #

  31. # => [{: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"}]
  32. JSON::Validator.fully_validate(schema, { "a" => "taco" }, :errors_as_objects => true)

  33. #
  34. # with the `:strict` option, all properties are considered to have `"required": true` and all objects `"additionalProperties": false`
  35. #

  36. # => true
  37. JSON::Validator.validate(schema, { "a" => 1, "b" => { "x" => 2 } }, :strict => true)
  38. # => false
  39. JSON::Validator.validate(schema, { "a" => 1, "b" => { "x" => 2 }, "c" => 3 }, :strict => true)
  40. # => false
  41. JSON::Validator.validate(schema, { "a" => 1 }, :strict => true)

  42. #
  43. # with the `:fragment` option, only a fragment of the schema is used for validation
  44. #

  45. # => true
  46. JSON::Validator.validate(schema, { "x" => 1 }, :fragment => "#/properties/b")
  47. # => false
  48. JSON::Validator.validate(schema, { "x" => 1 })

  49. #
  50. # with the `:validate_schema` option, the schema is validated (against the json schema spec) before the json is validated (against the specified schema)
  51. #

  52. # => true
  53. JSON::Validator.validate(schema, { "a" => 1 }, :validate_schema => true)
  54. # => false
  55. JSON::Validator.validate({ "required" => true }, { "a" => 1 }, :validate_schema => true)

  56. #
  57. # 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
  58. #

  59. # => true
  60. JSON::Validator.validate(schema, {}, :insert_defaults => true)
  61. # => false
  62. JSON::Validator.validate(schema, {})

  63. #
  64. # with the `:version` option, schemas conforming to older drafts of the json schema spec can be used
  65. #

  66. v2_schema = {
  67.   "type" => "object",
  68.   "properties" => {
  69.     "a" => {
  70.       "type" => "integer"
  71.     }
  72.   }
  73. }

  74. # => false
  75. JSON::Validator.validate(v2_schema, {}, :version => :draft2)
  76. # => true
  77. JSON::Validator.validate(v2_schema, {})

  78. #
  79. # 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)
  80. #

  81. # => true
  82. JSON::Validator.validate(schema, { "a" => 1 }, :parse_data => false)
  83. # => false
  84. JSON::Validator.validate(schema, '{ "a": 1 }', :parse_data => false)

  85. #
  86. # with the `:json` option, the json must be an unparsed json text (not a hash, a uri or a file path)
  87. #

  88. # => true
  89. JSON::Validator.validate(schema, '{ "a": 1 }', :json => true)
  90. # => "no implicit conversion of Hash into String"
  91. begin
  92.   JSON::Validator.validate(schema, { "a" => 1 }, :json => true)
  93. rescue TypeError => e
  94.   e.message
  95. end

  96. #
  97. # with the `:uri` option, the json must be a uri or file path (not a hash or a json text)
  98. #

  99. File.write("data.json", '{ "a": 1 }')

  100. # => true
  101. JSON::Validator.validate(schema, "data.json", :uri => true)
  102. # => "Can't convert Hash into String."
  103. begin
  104.   JSON::Validator.validate(schema, { "a"  => 1 }, :uri => true)
  105. rescue TypeError => e
  106.   e.message
  107. end

  108. #
  109. # with the `:clear_cache` option set to true, the internal cache of schemas is
  110. # cleared after validation (otherwise schemas are cached for efficiency)
  111. #

  112. File.write("schema.json", v2_schema.to_json)

  113. # => true
  114. JSON::Validator.validate("schema.json", {})

  115. File.write("schema.json", schema.to_json)

  116. # => true
  117. JSON::Validator.validate("schema.json", {}, :clear_cache => true)

  118. # => false
  119. JSON::Validator.validate("schema.json", {})
  120. ```

Extending Schemas


For this example, we are going to extend the JSON Schema Draft3 specification by adding a 'bitwise-and' property for validation.

  1. ``` ruby
  2. require "json-schema"

  3. class BitwiseAndAttribute < JSON::Schema::Attribute
  4.   def self.validate(current_schema, data, fragments, processor, validator, options = {})
  5.     if data.is_a?(Integer) && data & current_schema.schema['bitwise-and'].to_i == 0
  6.       message = "The property '#{build_fragment(fragments)}' did not evaluate  to true when bitwise-AND'd with  #{current_schema.schema['bitwise-or']}"
  7.       validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
  8.     end
  9.   end
  10. end

  11. class ExtendedSchema < JSON::Schema::Draft3
  12.   def initialize
  13.     super
  14.     @attributes["bitwise-and"] = BitwiseAndAttribute
  15.     @uri = JSON::Util::URI.parse("http://test.com/test.json")
  16.     @names = ["http://test.com/test.json"]
  17.   end

  18.   JSON::Validator.register_validator(self.new)
  19. end

  20. schema = {
  21.   "$schema" => "http://test.com/test.json",
  22.   "properties" => {
  23.     "a" => {
  24.       "bitwise-and" => 1
  25.     },
  26.     "b" => {
  27.       "type" => "string"
  28.     }
  29.   }
  30. }

  31. data = {
  32.   "a" => 0
  33. }

  34. data = {"a" => 1, "b" => "taco"}
  35. JSON::Validator.validate(schema,data) # => true
  36. data = {"a" => 1, "b" => 5}
  37. JSON::Validator.validate(schema,data) # => false
  38. data = {"a" => 0, "b" => "taco"}
  39. JSON::Validator.validate(schema,data) # => false
  40. ```

Custom format validation


The JSON schema standard allows custom formats in schema definitions which should be ignored by validators that do not support them. JSON::Schema allows registering procs as custom format validators which receive the value to be checked as parameter and must raise a JSON::Schema::CustomFormatError to indicate a format violation. The error message will be prepended by the property name, e.g. The property '#a'

  1. ``` ruby
  2. require "json-schema"

  3. format_proc = -> value {
  4.   raise JSON::Schema::CustomFormatError.new("must be 42") unless value == "42"
  5. }

  6. # register the proc for format 'the-answer' for draft4 schema
  7. JSON::Validator.register_format_validator("the-answer", format_proc, ["draft4"])

  8. # omitting the version parameter uses ["draft1", "draft2", "draft3", "draft4"] as default
  9. JSON::Validator.register_format_validator("the-answer", format_proc)

  10. # deregistering the custom validator
  11. # (also ["draft1", "draft2", "draft3", "draft4"] as default version)
  12. JSON::Validator.deregister_format_validator('the-answer', ["draft4"])

  13. # shortcut to restore the default formats for validators (same default as before)
  14. JSON::Validator.restore_default_formats(["draft4"])

  15. # with the validator registered as above, the following results in
  16. # ["The property '#a' must be 42"] as returned errors
  17. schema = {
  18.   "$schema" => "http://json-schema.org/draft-04/schema#",
  19.   "properties" => {
  20.     "a" => {
  21.       "type" => "string",
  22.       "format" => "the-answer",
  23.     }
  24.   }
  25. }
  26. errors = JSON::Validator.fully_validate(schema, {"a" => "23"})
  27. ```

Validating a JSON Schema


To validate that a JSON Schema conforms to the JSON Schema standard, you need to validate your schema against the metaschema for the appropriate JSON Schema Draft. All of the normal validation methods can be used for this. First retrieve the appropriate metaschema from the internal cache (using JSON::Validator.validator_for_name() or JSON::Validator.validator_for_uri() ) and then simply validate your schema against it.

  1. ``` ruby
  2. require "json-schema"

  3. schema = {
  4.   "type" => "object",
  5.   "properties" => {
  6.     "a" => {"type" => "integer"}
  7.   }
  8. }

  9. metaschema = JSON::Validator.validator_for_name("draft4").metaschema
  10. # => true
  11. JSON::Validator.validate(metaschema, schema)
  12. ```

Controlling Remote Schema Reading


In some cases, you may wish to prevent the JSON Schema library from making HTTP calls or reading local files in order to resolve $ref schemas. If you fully control all schemas which should be used by validation, this could be accomplished by registering all referenced schemas with the validator in advance:

  1. ``` ruby
  2. schema = JSON::Schema.new(some_schema_definition, Addressable::URI.parse('http://example.com/my-schema'))
  3. JSON::Validator.add_schema(schema)
  4. ```

If more extensive control is necessary, the JSON::Schema::Reader instance used can be configured in a few ways:

  1. ``` ruby
  2. # Change the default schema reader used
  3. JSON::Validator.schema_reader = JSON::Schema::Reader.new(:accept_uri => true, :accept_file => false)

  4. # For this validation call, use a reader which only accepts URIs from my-website.com
  5. schema_reader = JSON::Schema::Reader.new(
  6.   :accept_uri => proc { |uri| uri.host == 'my-website.com' }
  7. )
  8. JSON::Validator.validate(some_schema, some_object, :schema_reader => schema_reader)
  9. ```

The JSON::Schema::Reader interface requires only an object which responds to read(string) and returns a JSON::Schema instance. See the APIdocumentation for more information.

JSON Backends


The JSON Schema library currently supports the json and yajl-ruby backend JSON parsers. If either of these libraries are installed, they will be automatically loaded and used to parse any JSON strings supplied by the user.

If more than one of the supported JSON backends are installed, the yajl-ruby parser is used by default. This can be changed by issuing the following before validation:

  1. ``` ruby
  2. JSON::Validator.json_backend = :json
  3. ```

Optionally, the JSON Schema library supports using the MultiJSON library for selecting JSON backends. If the MultiJSON library is installed, it will be autoloaded.

Notes


The 'format' attribute is only validated for the following values:

date-time
date
time
ip-address (IPv4 address in draft1, draft2 and draft3)
ipv4 (IPv4 address in draft4)
ipv6
uri

All other 'format' attribute values are simply checked to ensure the instance value is of the correct datatype (e.g., an instance value is validated to be an integer or a float in the case of 'utc-millisec').

Additionally, JSON::Validator does not handle any json hyperschema attributes.

Transfer Notice


This plugin was originally authored by Iain Beeston. The maintainer preferred that Vox Pupuli take ownership of the module for future improvement and maintenance. Existing pull requests and issues were transferred, please fork and continue to contribute here.

License


This gem is licensed unter the MIT license.

Release information


To make a new release, please do:

update the version in VERSION.yml
Install gems with bundle install --with release --path .vendor
generate the changelog with bundle exec rake changelog
Check if the new version matches the closed issues/PRs in the changelog
Create a PR with it
After it got merged, push a tag. GitHub actions will do the actual release to rubygems and GitHub Packages
Last Updated: 2023-05-19 09:15:30