Class: Aspera::Schema::Validator
- Inherits:
-
Object
- Object
- Aspera::Schema::Validator
- Includes:
- Singleton
- Defined in:
- lib/aspera/schema/validator.rb
Overview
Validate values against the JSON schemas of the registry. Only schemas owned by ascli are validated: vendor API schemas are checked by the API itself.
Class Method Summary collapse
-
.instance ⇒ Validator
Returns the singleton instance of Validator.
Instance Method Summary collapse
-
#errors(value, path, partial: false) ⇒ Array<String>
Validate a value against a schema.
-
#initialize ⇒ Validator
constructor
A new instance of Validator.
Constructor Details
#initialize ⇒ Validator
Returns a new instance of Validator.
17 18 19 20 |
# File 'lib/aspera/schema/validator.rb', line 17 def initialize # compiled documents, key: [registry key, partial] @documents = {} end |
Class Method Details
.instance ⇒ Validator
Returns the singleton instance of Validator
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/aspera/schema/validator.rb', line 14 class Validator include Singleton def initialize # compiled documents, key: [registry key, partial] @documents = {} end # Validate a value against a schema. # @param value [Object] value to validate # @param path [String] schema path, e.g. `opts:components.schemas.HttpOptions` # @param partial [Boolean] `true`: value may be incomplete, `required` is not enforced, `null` values (removal) are ignored # @return [Array<String>] error messages, empty if valid or schema not validated def errors(value, path, partial: false) return [] unless path.is_a?(String) && Registry.owned?(path) key, dotted = path.split(':', 2) schema = document(key, partial) schema = schema.ref("#/#{dotted.split('.').map { |s| s.gsub('~', '~0').gsub('/', '~1') }.join('/')}") if dotted # JSON view of value: symbol keys and values become strings data = JSON.parse(JSON.generate(value)) data = without_null(data) if partial schema.validate(data).filter_map { |error| (error, partial) } end private # @param key [String] registry key # @param partial [Boolean] remove `required` from schema # @return [JSONSchemer::Schema] compiled schema document def document(key, partial) @documents[[key, partial]] ||= begin require 'json_schemer' root = Registry.instance.reader(key).current root = without_required(root) if partial = case root['openapi'] when /^3\.0\./ then JSONSchemer.openapi30 when /^3\.1\./ then JSONSchemer.openapi31 end ? JSONSchemer.schema(root, meta_schema: ) : JSONSchemer.schema(root) end end # @param node [Object] schema node # @return [Object] copy of node without `required` lists def without_required(node) case node when Hash then node.each_with_object({}) { |(k, v), h| h[k] = without_required(v) unless k.eql?('required') && v.is_a?(Array) } when Array then node.map { |e| without_required(e) } else node end end # @param node [Object] JSON value # @return [Object] copy of node without Hash entries whose value is `null` (entry removal requested by user) def without_null(node) case node when Hash then node.each_with_object({}) { |(k, v), h| h[k] = without_null(v) unless v.nil? } when Array then node.map { |e| without_null(e) } else node end end # @param error [Hash] json_schemer error # @param partial [Boolean] partial validation # @return [String, nil] message, or nil if error is ignored def (error, partial) return error['error'] unless error['type'].eql?('discriminator') property = error['schema'].dig('discriminator', 'propertyName') object = error['data'] # Partial value: selector may come from another source or a default return if partial && object.is_a?(Hash) && !object.key?(property) allowed = error['schema'].dig('discriminator', 'mapping')&.keys "value at `#{error['data_pointer']}/#{property}` is not one of: #{allowed}" end end |
Instance Method Details
#errors(value, path, partial: false) ⇒ Array<String>
Validate a value against a schema.
27 28 29 30 31 32 33 34 35 36 |
# File 'lib/aspera/schema/validator.rb', line 27 def errors(value, path, partial: false) return [] unless path.is_a?(String) && Registry.owned?(path) key, dotted = path.split(':', 2) schema = document(key, partial) schema = schema.ref("#/#{dotted.split('.').map { |s| s.gsub('~', '~0').gsub('/', '~1') }.join('/')}") if dotted # JSON view of value: symbol keys and values become strings data = JSON.parse(JSON.generate(value)) data = without_null(data) if partial schema.validate(data).filter_map { |error| (error, partial) } end |