Class: Verquest::Version

Inherits:
Object
  • Object
show all
Includes:
HelperMethods::RequiredProperties
Defined in:
lib/verquest/version.rb

Overview

Represents a specific version of an API request schema

The Version class manages the properties, schema generation, and mapping for a specific version of an API request. It holds the collection of properties that define the request structure and handles transforming between different property naming conventions.

Examples:

version = Verquest::Version.new(name: "2023-01")
version.add(Verquest::Properties::Field.new(name: :email, type: :string))
version.prepare

# Generate schema
schema = version.schema

# Get mapping
mapping = version.mapping

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from HelperMethods::RequiredProperties

#dependent_required_properties, #required_properties

Constructor Details

#initialize(name:) ⇒ Version

Initialize a new Version instance



57
58
59
60
61
# File 'lib/verquest/version.rb', line 57

def initialize(name:)
  @name = name.to_s
  @schema_options = {}
  @properties = {}
end

Instance Attribute Details

#descriptionString



51
# File 'lib/verquest/version.rb', line 51

attr_accessor :schema_options, :description

#external_mappingObject (readonly)

Returns the value of attribute external_mapping.



44
# File 'lib/verquest/version.rb', line 44

attr_reader :name, :properties, :schema, :validation_schema, :mapping, :transformer, :external_mapping

#mappingHash (readonly)



44
# File 'lib/verquest/version.rb', line 44

attr_reader :name, :properties, :schema, :validation_schema, :mapping, :transformer, :external_mapping

#nameString (readonly)



44
45
46
# File 'lib/verquest/version.rb', line 44

def name
  @name
end

#propertiesHash<Symbol, Verquest::Properties::Base> (readonly)



44
# File 'lib/verquest/version.rb', line 44

attr_reader :name, :properties, :schema, :validation_schema, :mapping, :transformer, :external_mapping

#schemaHash (readonly)



44
# File 'lib/verquest/version.rb', line 44

attr_reader :name, :properties, :schema, :validation_schema, :mapping, :transformer, :external_mapping

#schema_optionsHash



51
52
53
# File 'lib/verquest/version.rb', line 51

def schema_options
  @schema_options
end

#transformerVerquest::Transformer (readonly)



44
# File 'lib/verquest/version.rb', line 44

attr_reader :name, :properties, :schema, :validation_schema, :mapping, :transformer, :external_mapping

#validation_schemaHash (readonly)



44
# File 'lib/verquest/version.rb', line 44

attr_reader :name, :properties, :schema, :validation_schema, :mapping, :transformer, :external_mapping

Instance Method Details

#add(property) ⇒ Verquest::Properties::Base

Add a property to this version



67
68
69
# File 'lib/verquest/version.rb', line 67

def add(property)
  properties[property.name] = property
end

#copy_from(version, exclude_properties: []) ⇒ void

This method returns an undefined value.

Copy properties from another version

Raises:

  • (ArgumentError)

    If version is not a Verquest::Version instance



94
95
96
97
98
99
100
101
102
# File 'lib/verquest/version.rb', line 94

def copy_from(version, exclude_properties: [])
  raise ArgumentError, "Expected a Verquest::Version instance" unless version.is_a?(Version)

  version.properties.values.each do |property|
    next if exclude_properties.include?(property.name.to_sym)

    add(property)
  end
end

#has?(property_name) ⇒ Boolean

Check if this version has a property with the given name



84
85
86
# File 'lib/verquest/version.rb', line 84

def has?(property_name)
  properties.key?(property_name.to_s)
end

#map_params(params) ⇒ Hash

Map request parameters to internal representation using the transformer



195
196
197
# File 'lib/verquest/version.rb', line 195

def map_params(params)
  transformer.call(params)
end

#mapping_for(property) ⇒ Hash

Get the mapping for a specific property

Raises:



183
184
185
186
187
188
189
# File 'lib/verquest/version.rb', line 183

def mapping_for(property)
  raise PropertyNotFoundError.new("Property '#{property}' is not defined on '#{name}'") unless has?(property)

  {}.tap do |mapping|
    properties[property.to_s].mapping(key_prefix: [], value_prefix: [], mapping: mapping, version: name)
  end
end

#preparevoid

This method returns an undefined value.

Prepare this version by generating schema and creating transformer



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/verquest/version.rb', line 107

def prepare
  return if frozen?

  unless schema_options.key?("additionalProperties")
    schema_options["additionalProperties"] = Verquest.configuration.default_additional_properties
  end

  schema_options.delete_if { |_, v| v.nil? }

  prepare_schema
  prepare_validation_schema
  prepare_mapping
  prepare_external_mapping
  @transformer = Transformer.new(mapping: mapping)

  freeze
end

#prepare_external_mappingHash (private)

Prepares the inverted parameter mapping for this version

Inverts the standard mapping to create a reverse lookup from internal attribute names back to external parameter names. This is useful when transforming internal data back to the external API representation.

See Also:



262
263
264
# File 'lib/verquest/version.rb', line 262

def prepare_external_mapping
  @external_mapping = mapping.invert.freeze
end

#prepare_mappingHash (private)

Prepares the parameter mapping for this version

Collects mappings from all properties in this version and checks for duplicate mappings, which would cause conflicts during transformation.

Raises:



243
244
245
246
247
248
249
250
251
# File 'lib/verquest/version.rb', line 243

def prepare_mapping
  @mapping = properties.values.each_with_object({}) do |property, mapping|
    property.mapping(key_prefix: [], value_prefix: [], mapping: mapping, version: name)
  end

  if (duplicates = mapping.keys.select { |k| mapping.values.count(k) > 1 }).any?
    raise MappingError.new("Mapping must be unique. Found duplicates in version '#{name}': #{duplicates.join(", ")}")
  end
end

#prepare_schemaHash (private)

Generates the JSON schema for this version

Creates a schema object with type, description, required properties, and property definitions based on the properties in this version. The schema is frozen to prevent modification after preparation.



208
209
210
211
212
213
214
215
216
217
# File 'lib/verquest/version.rb', line 208

def prepare_schema
  @schema = {
    "type" => "object",
    "description" => description,
    "required" => required_properties,
    "properties" => properties.transform_values { |property| property.to_schema[property.name] }
  }.merge(schema_options).tap do |schema|
    schema["dependentRequired"] = dependent_required_properties if dependent_required_properties.any?
  end.freeze
end

#prepare_validation_schemaHash (private)

Generates the validation schema for this version

Similar to prepare_schema but specifically for validation purposes. The validation schema will include all referenced components and properties.



225
226
227
228
229
230
231
232
233
234
# File 'lib/verquest/version.rb', line 225

def prepare_validation_schema
  @validation_schema = {
    "type" => "object",
    "description" => description,
    "required" => required_properties,
    "properties" => properties.transform_values { |property| property.to_validation_schema(version: name)[property.name] }
  }.merge(schema_options).tap do |schema|
    schema["dependentRequired"] = dependent_required_properties if dependent_required_properties.any?
  end.freeze
end

#remove(property_name) ⇒ Verquest::Properties::Base

Remove a property from this version by name

Raises:



76
77
78
# File 'lib/verquest/version.rb', line 76

def remove(property_name)
  properties.delete(property_name.to_s) || raise(PropertyNotFoundError.new("Property '#{property_name}' is not defined on '#{name}'"))
end

#valid_schema?Boolean

Validate the schema against the metaschema



128
129
130
131
132
133
# File 'lib/verquest/version.rb', line 128

def valid_schema?
  JSONSchemer.valid_schema?(
    validation_schema,
    meta_schema: Verquest.configuration.json_schema_uri
  )
end

#validate_params(params:) ⇒ Array<Hash>

Validate request parameters against the version’s validation schema



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/verquest/version.rb', line 161

def validate_params(params:)
  schemer = JSONSchemer.schema(
    validation_schema,
    meta_schema: Verquest.configuration.json_schema_uri,
    insert_property_defaults: Verquest.configuration.insert_property_defaults
  )

  schemer.validate(params).map do |error|
    {
      pointer: error["data_pointer"],
      type: error["type"],
      message: error["error"],
      details: error["details"]
    }
  end
end

#validate_schemaArray<Hash>

Validate the schema against the metaschema and return detailed errors

This method validates the schema against the configured JSON Schema metaschema and returns detailed validation errors if any are found. It uses the JSONSchemer library with the schema version specified in the configuration.

See Also:



143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/verquest/version.rb', line 143

def validate_schema
  JSONSchemer.validate_schema(
    validation_schema,
    meta_schema: Verquest.configuration.json_schema_uri
  ).map do |error|
    {
      pointer: error["data_pointer"],
      type: error["type"],
      message: error["error"],
      details: error["details"]
    }
  end
end