Class: Servus::Support::Validator
- Inherits:
-
Object
- Object
- Servus::Support::Validator
- Defined in:
- lib/servus/support/validator.rb
Overview
Handles JSON Schema validation for service arguments and results.
The Validator class provides automatic validation of service inputs and outputs against JSON Schema definitions. Schemas can be defined as inline constants (ARGUMENTS_SCHEMA, RESULT_SCHEMA) or as external JSON files.
Class Method Summary collapse
-
.cache ⇒ Hash
private
Returns the current schema cache.
-
.clear_cache! ⇒ Hash
Clears the schema cache.
-
.fetch_schema_from_sources(dsl_schema, inline_schema_constant, schema_path) ⇒ Hash?
private
Fetches schema from DSL, inline constant, or file.
-
.load_schema(service_class, type) ⇒ Hash?
private
Loads and caches a schema for a service.
-
.parse_service_namespace(service_class) ⇒ String
private
Converts service class name to file path namespace.
-
.validate_arguments!(service_class, args) ⇒ Boolean
private
Validates service arguments against the ARGUMENTS_SCHEMA.
-
.validate_event_payload!(handler_class, payload) ⇒ Boolean
private
Validates event payload against the handler's payload schema.
-
.validate_result!(service_class, result) ⇒ Servus::Support::Response
private
Validates service result data against the RESULT_SCHEMA.
Class Method Details
.cache ⇒ Hash
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the current schema cache.
179 180 181 |
# File 'lib/servus/support/validator.rb', line 179 def self.cache @schema_cache end |
.clear_cache! ⇒ Hash
Clears the schema cache.
Useful in development when schema files are modified, or in tests to ensure fresh schema loading between test cases.
171 172 173 |
# File 'lib/servus/support/validator.rb', line 171 def self.clear_cache! @schema_cache = {} end |
.fetch_schema_from_sources(dsl_schema, inline_schema_constant, schema_path) ⇒ Hash?
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Fetches schema from DSL, inline constant, or file.
Implements the schema resolution precedence:
- DSL-defined schema (if provided)
- Inline constant (if provided)
- File at schema_path (if exists)
- nil (no schema found)
197 198 199 200 201 202 203 204 205 |
# File 'lib/servus/support/validator.rb', line 197 def self.fetch_schema_from_sources(dsl_schema, inline_schema_constant, schema_path) if dsl_schema dsl_schema.with_indifferent_access elsif inline_schema_constant inline_schema_constant.with_indifferent_access elsif File.exist?(schema_path) JSON.load_file(schema_path).with_indifferent_access end end |
.load_schema(service_class, type) ⇒ Hash?
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Loads and caches a schema for a service.
Implements a three-tier lookup strategy:
- Check for schema defined via DSL method (service_class.arguments_schema/result_schema)
- Check for inline constant (ARGUMENTS_SCHEMA or RESULT_SCHEMA)
- Fall back to JSON file in app/schemas/services/namespace/type.json
Schemas are cached after first load for performance.
rubocop:disable Metrics/MethodLength
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/servus/support/validator.rb', line 135 def self.load_schema(service_class, type) # Get service path based on class name (e.g., "process_payment" from "Servus::ProcessPayment::Service") service_namespace = parse_service_namespace(service_class) schema_path = Servus.config.schema_path_for(service_namespace, type) # Return from cache if available return @schema_cache[schema_path] if @schema_cache.key?(schema_path) # Check for DSL-defined schema first dsl_schema = if type == 'arguments' service_class.arguments_schema else service_class.result_schema end inline_schema_constant_name = "#{service_class}::#{type.upcase}_SCHEMA" inline_schema_constant = if Object.const_defined?(inline_schema_constant_name) Object.const_get(inline_schema_constant_name) end @schema_cache[schema_path] = fetch_schema_from_sources(dsl_schema, inline_schema_constant, schema_path) @schema_cache[schema_path] end |
.parse_service_namespace(service_class) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Converts service class name to file path namespace.
Transforms a class name like "Services::ProcessPayment::Service" into "services/process_payment" for locating schema files.
220 221 222 223 224 |
# File 'lib/servus/support/validator.rb', line 220 def self.parse_service_namespace(service_class) service_class.name.split('::')[..-2].map do |s| s.gsub(/([a-z])([A-Z])/, '\1_\2').downcase end.join('/') end |
.validate_arguments!(service_class, args) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Validates service arguments against the ARGUMENTS_SCHEMA.
Checks arguments against either an inline ARGUMENTS_SCHEMA constant or a file-based schema at app/schemas/services/namespace/arguments.json. Validation is skipped if no schema is defined.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/servus/support/validator.rb', line 46 def self.validate_arguments!(service_class, args) schema = load_schema(service_class, 'arguments') return true unless schema # Skip validation if no schema exists serialized_result = args.as_json validation_errors = JSON::Validator.fully_validate(schema, serialized_result) if validation_errors.any? = "Invalid arguments for #{service_class.name}: #{validation_errors.join(', ')}" raise Servus::Base::ValidationError, end true end |
.validate_event_payload!(handler_class, payload) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Validates event payload against the handler's payload schema.
105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/servus/support/validator.rb', line 105 def self.validate_event_payload!(handler_class, payload) schema = handler_class.payload_schema return true unless schema serialized_payload = payload.as_json validation_errors = JSON::Validator.fully_validate(schema, serialized_payload) if validation_errors.any? raise Servus::Support::Errors::ValidationError, "Invalid payload for event :#{handler_class.event_name}: #{validation_errors.join(', ')}" end true end |
.validate_result!(service_class, result) ⇒ Servus::Support::Response
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Validates service result data against the RESULT_SCHEMA.
Checks the result.data against either an inline RESULT_SCHEMA constant or a file-based schema at app/schemas/services/namespace/result.json. Only validates successful responses; failures are skipped.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/servus/support/validator.rb', line 76 def self.validate_result!(service_class, result) return result unless result.success? schema = load_schema(service_class, 'result') return result unless schema # Skip validation if no schema exists serialized_result = result.data.as_json validation_errors = JSON::Validator.fully_validate(schema, serialized_result) if validation_errors.any? = "Invalid result structure from #{service_class.name}: #{validation_errors.join(', ')}" raise Servus::Base::ValidationError, end result end |