verquest 0.2.1 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3937cd4b94f0a041133b0f36400e377afade0d8cc3c15bbc4b4f8ef601b8cf91
4
- data.tar.gz: c8e2ae6eea78d6840cc23c6ee461322fe2a7e79292e8c4cacf7ad0153a9bf215
3
+ metadata.gz: 0ccc6bfd2d16a987d2ed8ae6c04a9fbfd72a0ed58f00699221193ef76e764cd0
4
+ data.tar.gz: '0026964f349c5d17f41b18cd7f32431519c46f1530fe92a535488abcd202a86e'
5
5
  SHA512:
6
- metadata.gz: c7f9d528de6b8b0f7344ed02b52873a99c2a432a6c1d058e2fd25633bdc192c8ab68cd074e561add9567146b427a40256ba43bada339065b8138b9be8f02c9c4
7
- data.tar.gz: d94a551e3ba5804711630c54a33bd2717c711c8792565dfdaacdcfad902ca446a21a96d50fe03487fef7c4109d41efaf03db9b8a5c7cdb02699d8a5307144732
6
+ metadata.gz: dba0dc768c80d2f51cfb74a9c93483218c8d3f28fffffe01b41d250e78f0d2e504ba64af6ea2dd723de22640170b2151f860424bcdc5ad05b29d24fa694a5081
7
+ data.tar.gz: 662c43fb095decd144c50afece842467ff96705bbe4a51f27a347a2fdf6041a0bc98895274f280a1441ca88f445a1820d519fc280f9304bc26826f44ea9fcb23
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.0] - 2025-06-25
4
+
5
+ ### Breaking Changes
6
+ - **BREAKING:** Replace `json-schema` gem with `json_schemer` for support of newer JSON Schema specifications (set the lasest by default).
7
+ - **BREAKING:** Schema and validation schema now uses string keys instead of symbols.
8
+
9
+ ### Added
10
+ - Allow insert default values for properties when validation is used.
3
11
 
4
12
  ## [0.2.1] - 2025-06-22
5
13
 
data/README.md CHANGED
@@ -128,49 +128,53 @@ UserCreateRequest.to_schema(version: "2025-06")
128
128
  Output:
129
129
  ```ruby
130
130
  {
131
- type: :object,
132
- description: "User Create Request",
133
- required: [:first_name, :last_name, :email, :address],
134
- properties: {
135
- first_name: {type: :string, description: "The first name of the user", maxLength: 50},
136
- last_name: {type: :string, description: "The last name of the user", maxLength: 50},
137
- email: {type: :string, format: "email", description: "The email address of the user"},
138
- birth_date: {type: :string, format: "date", description: "The birth date of the user"},
139
- address: {"$ref": "#/components/schemas/AddressCreateRequest"},
140
- permissions: {
141
- type: :array,
142
- items: {
143
- type: :object,
144
- required: [:name],
145
- properties: {
146
- name: {type: :string, description: "Name of the permission"},
147
- read: {type: :boolean, description: "Permission to read"},
148
- write: {type: :boolean, description: "Permission to write"}
131
+ "type" => "object",
132
+ "description" => "User Create Request",
133
+ "required" => ["first_name", "last_name", "email", "address"],
134
+ "properties" => {
135
+ "first_name" => {"type" => "string", "description" => "The first name of the user", "maxLength" => 50},
136
+ "last_name" => {"type" => "string", "description" => "The last name of the user", "maxLength" => 50},
137
+ "email" => {"type" => "string", "format" => "email", "description" => "The email address of the user"},
138
+ "birth_date" => {"type" => "string", "format" => "date", "description" => "The birth date of the user"},
139
+ "address" => {"$ref" => "#/components/schemas/AddressCreateRequest"},
140
+ "permissions" => {
141
+ "type" => "array",
142
+ "items" => {
143
+ "type" => "object",
144
+ "required" => ["name"],
145
+ "properties" => {
146
+ "name" => {"type" => "string", "description" => "Name of the permission"},
147
+ "read" => {"type" => "boolean", "description" => "Permission to read"},
148
+ "write" => {"type" => "boolean", "description" => "Permission to write"}
149
149
  }
150
- },
151
- description: "Permissions associated with the user"
150
+ },
151
+ "description" => "Permissions associated with the user"
152
152
  },
153
- role: {type: :string, description: "Role of the user", enum: ["member", "manager"], default: "member"},
154
- profile_details: {
155
- type: :object,
156
- required: [],
157
- properties: {
158
- bio: {type: :string, description: "Short biography of the user"},
159
- hobbies: {type: :array, items: {type: :string}, description: "Tags associated with the user"},
160
- social_links: {
161
- type: :object,
162
- required: [],
163
- properties: {
164
- github: {type: :string, format: "uri", description: "GitHub profile URL"},
165
- mastodon: {type: :string, format: "uri", description: "Mastodon profile URL"}
166
- },
167
- description: "Some social networks"
153
+ "role" => {
154
+ "type" => "string",
155
+ "description" => "Role of the user",
156
+ "enum" => ["member", "manager"],
157
+ "default" => "member"
158
+ },
159
+ "profile_details" => {
160
+ "type" => "object",
161
+ "required" => [],
162
+ "properties" => {
163
+ "bio" => {"type" => "string", "description" => "Short biography of the user"},
164
+ "hobbies" => {"type" => "array", "items" => {"type" => "string"}, "description" => "Tags associated with the user"},
165
+ "social_links" => {
166
+ "type" => "object",
167
+ "required" => [],
168
+ "properties" => {
169
+ "github" => {"type" => "string", "format" => "uri", "description" => "GitHub profile URL"},
170
+ "mastodon" => {"type" => "string", "format" => "uri", "description" => "Mastodon profile URL"}
171
+ },
172
+ "description" => "Some social networks"
168
173
  }
169
174
  }
170
175
  }
171
176
  },
172
- additionalProperties: false
173
- }
177
+ "additionalProperties" => false}
174
178
  ```
175
179
 
176
180
  ### JSON schema for validation
@@ -184,59 +188,61 @@ UserCreateRequest.to_validation_schema(version: "2025-06")
184
188
  Output:
185
189
  ```ruby
186
190
  {
187
- type: :object,
188
- description: "User Create Request",
189
- required: [:first_name, :last_name, :email, :address],
190
- properties: {
191
- first_name: {type: :string, description: "The first name of the user", maxLength: 50},
192
- last_name: {type: :string, description: "The last name of the user", maxLength: 50},
193
- email: {type: :string, format: "email", description: "The email address of the user"},
194
- birth_date: {type: :string, format: "date", description: "The birth date of the user"},
195
- address: { # from the AddressCreateRequest
196
- type: :object,
197
- description: "Address Create Request",
198
- required: [:street, :city, :postal_code, :country],
199
- properties: {
200
- street: {type: :string, description: "Street address"},
201
- city: {type: :string, description: "City of residence"},
202
- postal_code: {type: :string, description: "Postal code"},
203
- country: {type: :string, description: "Country of residence"}
191
+ "type" => "object",
192
+ "description" => "User Create Request",
193
+ "required" => ["first_name", "last_name", "email", "address"],
194
+ "properties" => {
195
+ "first_name" => {"type" => "string", "description" => "The first name of the user", "maxLength" => 50},
196
+ "last_name" => {"type" => "string", "description" => "The last name of the user", "maxLength" => 50},
197
+ "email" => {"type" => "string", "format" => "email", "description" => "The email address of the user"},
198
+ "birth_date" => {"type" => "string", "format" => "date", "description" => "The birth date of the user"},
199
+ "address" => { # from the AddressCreateRequest
200
+ "type" => "object",
201
+ "description" => "Address Create Request",
202
+ "required" => ["street", "city", "postal_code", "country"],
203
+ "properties" => {
204
+ "street" => {"type" => "string", "description" => "Street address"},
205
+ "city" => {"type" => "string", "description" => "City of residence"},
206
+ "postal_code" => {"type" => "string", "description" => "Postal code"},
207
+ "country" => {"type" => "string", "description" => "Country of residence"}
204
208
  },
205
- additionalProperties: false
209
+ "additionalProperties" => false
206
210
  },
207
- permissions: {
208
- type: :array,
209
- items: {
210
- type: :object,
211
- required: [:name],
212
- properties: {
213
- name: {type: :string, description: "Name of the permission"},
214
- read: {type: :boolean, description: "Permission to read"},
215
- write: {type: :boolean, description: "Permission to write"}
211
+ "permissions" => {
212
+ "type" => "array",
213
+ "items" => {
214
+ "type" => "object", "required" => ["name"],
215
+ "properties" => {
216
+ "name" => {"type" => "string", "description" => "Name of the permission"},
217
+ "read" => {"type" => "boolean", "description" => "Permission to read"},
218
+ "write" => {"type" => "boolean", "description" => "Permission to write"}
216
219
  }
217
220
  },
218
- description: "Permissions associated with the user"
221
+ "description" => "Permissions associated with the user"
219
222
  },
220
- role: {type: :string, description: "Role of the user", enum: ["member", "manager"], default: "member"},
221
- profile_details: {
222
- type: :object,
223
- required: [],
224
- properties: {
225
- bio: {type: :string, description: "Short biography of the user"},
226
- hobbies: {type: :array, items: {type: :string}, description: "Tags associated with the user"},
227
- social_links: {
228
- type: :object,
229
- required: [],
230
- properties: {
231
- github: {type: :string, format: "uri", description: "GitHub profile URL"},
232
- mastodon: {type: :string, format: "uri", description: "Mastodon profile URL"}
233
- },
234
- description: "Some social networks"
235
- }
223
+ "role" => {
224
+ "type" => "string",
225
+ "description" => "Role of the user",
226
+ "enum" => ["member", "manager"],
227
+ "default" => "member"
228
+ },
229
+ "profile_details" => {"type" => "object",
230
+ "required" => [],
231
+ "properties" => {
232
+ "bio" => {"type" => "string", "description" => "Short biography of the user"},
233
+ "hobbies" => {"type" => "array", "items" => {"type" => "string"}, "description" => "Tags associated with the user"},
234
+ "social_links" => {
235
+ "type" => "object",
236
+ "required" => [],
237
+ "properties" => {
238
+ "github" => {"type" => "string", "format" => "uri", "description" => "GitHub profile URL"},
239
+ "mastodon" => {"type" => "string", "format" => "uri", "description" => "Mastodon profile URL"}
240
+ },
241
+ "description" => "Some social networks"}
236
242
  }
237
243
  }
238
244
  },
239
- additionalProperties: false
245
+ "additionalProperties" => false
240
246
  }
241
247
  ```
242
248
 
@@ -64,7 +64,7 @@ module Verquest
64
64
  instance_exec(&block)
65
65
  ensure
66
66
  version.description ||= versions.description
67
- version.schema_options = versions.schema_options.merge(version.schema_options)
67
+ version.schema_options = versions.schema_options.merge(version.schema_options).transform_keys(&:to_s)
68
68
  version.prepare
69
69
  end
70
70
 
@@ -12,7 +12,8 @@ module Verquest
12
12
  # @param version [String, nil] Specific version to use, defaults to configuration setting
13
13
  # @param validate [Boolean, nil] Whether to validate the params, defaults to configuration setting
14
14
  # @param remove_extra_root_keys [Boolean, nil] Whether to remove extra keys at the root level, defaults to configuration setting
15
- # @return [Verquest::Result] Success result with mapped params or failure result with validation errors
15
+ # @return [Verquest::Result, Hash, Exception] When validation_error_handling is :result, returns a Success result with mapped params or Failure result with validation errors.
16
+ # When validation_error_handling is :raise, returns mapped params directly or raises InvalidParamsError with validation errors.
16
17
  def process(params, version: nil, validate: nil, remove_extra_root_keys: nil)
17
18
  validate = Verquest.configuration.validate_params if validate.nil?
18
19
  remove_extra_root_keys = Verquest.configuration.remove_extra_root_keys if remove_extra_root_keys.nil?
@@ -23,7 +24,7 @@ module Verquest
23
24
  params = params.to_unsafe_h if params.respond_to?(:to_unsafe_h)
24
25
  params = params.slice(*version_class.properties.keys) if remove_extra_root_keys
25
26
 
26
- if validate && (validation_result = version_class.validate_params(params: params, component_reference: to_ref, remove_extra_root_keys: remove_extra_root_keys)) && validation_result.any?
27
+ if validate && (validation_result = version_class.validate_params(params: params)) && validation_result.any?
27
28
  case Verquest.configuration.validation_error_handling
28
29
  when :raise
29
30
  raise InvalidParamsError.new("Validation failed", errors: validation_result)
@@ -59,7 +60,7 @@ module Verquest
59
60
  version = resolve(version)
60
61
 
61
62
  if property
62
- version.validation_schema[:properties][property]
63
+ version.validation_schema["properties"][property.to_s]
63
64
  else
64
65
  version.validation_schema
65
66
  end
@@ -76,7 +77,7 @@ module Verquest
76
77
  # Returns the mapping for a specific version or property
77
78
  #
78
79
  # @param version [String, nil] Specific version to use, defaults to configuration setting
79
- # @param property [Symbol, nil] Specific property to retrieve mapping for
80
+ # @param property [String, Symbol, nil] Specific property to retrieve mapping for
80
81
  # @return [Hash] The mapping configuration
81
82
  def mapping(version: nil, property: nil)
82
83
  version = resolve(version)
@@ -90,7 +91,7 @@ module Verquest
90
91
 
91
92
  # Returns the JSON reference for the request or a specific property
92
93
  #
93
- # @param property [Symbol, nil] Specific property to retrieve reference for
94
+ # @param property [String, Symbol, nil] Specific property to retrieve reference for
94
95
  # @return [String] The JSON reference for the request or property
95
96
  def to_ref(property: nil)
96
97
  base = "#/components/schemas/#{component_name}"
@@ -11,13 +11,23 @@ module Verquest
11
11
  # config.current_version = -> { Current.api_version }
12
12
  # end
13
13
  class Configuration
14
+ SCHEMAS = {
15
+ draft4: JSONSchemer::Draft4,
16
+ draft6: JSONSchemer::Draft6,
17
+ draft7: JSONSchemer::Draft7,
18
+ draft2019_09: JSONSchemer::Draft201909,
19
+ draft2020_12: JSONSchemer::Draft202012,
20
+ openapi30: JSONSchemer::OpenAPI30,
21
+ openapi31: JSONSchemer::OpenAPI31
22
+ }.freeze
23
+
14
24
  # @!attribute [rw] validate_params
15
25
  # Controls whether parameters are automatically validated against the schema
16
26
  # @return [Boolean] true if validation is enabled, false otherwise
17
27
  #
18
28
  # @!attribute [rw] json_schema_version
19
- # The JSON Schema draft version to use for validation and schema generation (see the json-schema gem)
20
- # @return [Symbol] The JSON Schema version (e.g., :draft4, :draft5)
29
+ # The JSON Schema draft version to use for validation and schema generation (see Configuration::SCHEMAS)
30
+ # @return [Symbol] The JSON Schema version (e.g., :draft2020_12, :draft2019_09, :draft7)
21
31
  #
22
32
  # @!attribute [rw] validation_error_handling
23
33
  # Controls how errors during parameter processing are handled
@@ -26,7 +36,11 @@ module Verquest
26
36
  # @!attribute [rw] remove_extra_root_keys
27
37
  # Controls if extra root keys not defined in the schema should be removed from the parameters
28
38
  # @return [Boolean] true if extra keys should be removed, false otherwise
29
- attr_accessor :validate_params, :json_schema_version, :validation_error_handling, :remove_extra_root_keys
39
+ #
40
+ # @!attribute [rw] insert_property_defaults
41
+ # Controls whether default values defined in property schemas should be inserted when not provided during validation
42
+ # @return [Boolean] true if default values should be inserted, false otherwise
43
+ attr_accessor :validate_params, :json_schema_version, :validation_error_handling, :remove_extra_root_keys, :insert_property_defaults
30
44
 
31
45
  # @!attribute [r] current_version
32
46
  # A callable object that returns the current API version to use when not explicitly specified
@@ -42,10 +56,11 @@ module Verquest
42
56
  # @return [Configuration] A new configuration instance with default settings
43
57
  def initialize
44
58
  @validate_params = true
45
- @json_schema_version = :draft6
59
+ @json_schema_version = :draft2020_12
46
60
  @validation_error_handling = :raise # or :result
47
61
  @remove_extra_root_keys = true
48
62
  @version_resolver = VersionResolver
63
+ @insert_property_defaults = true
49
64
  end
50
65
 
51
66
  # Sets the current version strategy using a callable object
@@ -69,5 +84,20 @@ module Verquest
69
84
 
70
85
  @version_resolver = version_resolver
71
86
  end
87
+
88
+ # Gets the JSON Schema class based on the configured version
89
+ #
90
+ # @return [Class] The JSON Schema class matching the configured version
91
+ # @raise [ArgumentError] If the configured json_schema_version is not supported
92
+ def json_schema
93
+ SCHEMAS[json_schema_version] || raise(ArgumentError, "Unsupported JSON Schema version: #{json_schema_version}")
94
+ end
95
+
96
+ # Gets the JSON Schema URI for the configured schema version
97
+ #
98
+ # @return [String] The base URI for the configured JSON Schema version
99
+ def json_schema_uri
100
+ json_schema::BASE_URI.to_s
101
+ end
72
102
  end
73
103
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Verquest
4
- GEM_VERSION = "0.2.1"
4
+ GEM_VERSION = "0.3.0"
5
5
  end
@@ -16,8 +16,8 @@ module Verquest
16
16
  class Array < Base
17
17
  # Initialize a new Array property
18
18
  #
19
- # @param name [Symbol] The name of the property
20
- # @param type [Symbol] The type of items in the array
19
+ # @param name [String, Symbol] The name of the property
20
+ # @param type [String, Symbol] The type of items in the array
21
21
  # @param map [String, nil] The mapping path for this property (nil for no explicit mapping)
22
22
  # @param required [Boolean] Whether this property is required
23
23
  # @param schema_options [Hash] Additional JSON schema options for this property
@@ -25,11 +25,11 @@ module Verquest
25
25
  def initialize(name:, type:, map: nil, required: false, **schema_options)
26
26
  raise ArgumentError, "You can not map array to the root" if map == "/"
27
27
 
28
- @name = name
29
- @type = type
28
+ @name = name.to_s
29
+ @type = type.to_s
30
30
  @map = map
31
31
  @required = required
32
- @schema_options = schema_options
32
+ @schema_options = schema_options&.transform_keys(&:to_s)
33
33
  end
34
34
 
35
35
  # Generate JSON schema definition for this array property
@@ -38,16 +38,16 @@ module Verquest
38
38
  def to_schema
39
39
  {
40
40
  name => {
41
- type: :array,
42
- items: {type: type}
41
+ "type" => "array",
42
+ "items" => {"type" => type}
43
43
  }.merge(schema_options)
44
44
  }
45
45
  end
46
46
 
47
47
  # Create mapping for this array property
48
48
  #
49
- # @param key_prefix [Array<Symbol>] Prefix for the source key
50
- # @param value_prefix [Array<Symbol>] Prefix for the target value
49
+ # @param key_prefix [Array<String>] Prefix for the source key
50
+ # @param value_prefix [Array<String>] Prefix for the target value
51
51
  # @param mapping [Hash] The mapping hash to be updated
52
52
  # @param version [String, nil] The version to create mapping for, defaults to configuration setting
53
53
  # @return [Hash] The updated mapping hash
@@ -11,7 +11,7 @@ module Verquest
11
11
  # @abstract Subclass and override {#to_schema}, {#mapping} to implement
12
12
  class Base
13
13
  # @!attribute [rw] name
14
- # @return [Symbol] The name of the property
14
+ # @return [String] The name of the property
15
15
  # @!attribute [rw] required
16
16
  # @return [Boolean] Whether this property is required
17
17
  # @!attribute [rw] map
@@ -43,7 +43,7 @@ module Verquest
43
43
 
44
44
  # Creates mapping for this property
45
45
  # @abstract
46
- # @param key_prefix [Array<Symbol>] Prefix for the source key
46
+ # @param key_prefix [Array<String>] Prefix for the source key
47
47
  # @param value_prefix [Array<String>] Prefix for the target value
48
48
  # @param mapping [Hash] The mapping hash to be updated
49
49
  # @param version [String, nil] The version to create mapping for
@@ -20,7 +20,7 @@ module Verquest
20
20
  class Collection < Base
21
21
  # Initialize a new Collection property
22
22
  #
23
- # @param name [Symbol] The name of the property
23
+ # @param name [String, Symbol] The name of the property
24
24
  # @param item [Verquest::Base, nil] Optional reference to an external schema class
25
25
  # @param required [Boolean] Whether this property is required
26
26
  # @param map [String, nil] The mapping path for this property
@@ -31,11 +31,11 @@ module Verquest
31
31
 
32
32
  @properties = {}
33
33
 
34
- @name = name
34
+ @name = name.to_s
35
35
  @item = item
36
36
  @required = required
37
37
  @map = map
38
- @schema_options = schema_options
38
+ @schema_options = schema_options&.transform_keys(&:to_s)
39
39
  end
40
40
 
41
41
  # Add a child property to this collection's item definition
@@ -60,20 +60,20 @@ module Verquest
60
60
  if has_item?
61
61
  {
62
62
  name => {
63
- type: :array,
64
- items: {
65
- "$ref": item.to_ref
63
+ "type" => "array",
64
+ "items" => {
65
+ "$ref" => item.to_ref
66
66
  }
67
67
  }.merge(schema_options)
68
68
  }
69
69
  else
70
70
  {
71
71
  name => {
72
- type: :array,
73
- items: {
74
- type: :object,
75
- required: properties.values.select(&:required).map(&:name),
76
- properties: properties.transform_values { |property| property.to_schema[property.name] }
72
+ "type" => "array",
73
+ "items" => {
74
+ "type" => "object",
75
+ "required" => properties.values.select(&:required).map(&:name),
76
+ "properties" => properties.transform_values { |property| property.to_schema[property.name] }
77
77
  }
78
78
  }.merge(schema_options)
79
79
  }
@@ -88,18 +88,18 @@ module Verquest
88
88
  if has_item?
89
89
  {
90
90
  name => {
91
- type: :array,
92
- items: item.to_validation_schema(version: version)
91
+ "type" => "array",
92
+ "items" => item.to_validation_schema(version: version)
93
93
  }.merge(schema_options)
94
94
  }
95
95
  else
96
96
  {
97
97
  name => {
98
- type: :array,
99
- items: {
100
- type: :object,
101
- required: properties.values.select(&:required).map(&:name),
102
- properties: properties.transform_values { |property| property.to_validation_schema(version: version)[property.name] }
98
+ "type" => "array",
99
+ "items" => {
100
+ "type" => "object",
101
+ "required" => properties.values.select(&:required).map(&:name),
102
+ "properties" => properties.transform_values { |property| property.to_validation_schema(version: version)[property.name] }
103
103
  }
104
104
  }.merge(schema_options)
105
105
  }
@@ -118,7 +118,7 @@ module Verquest
118
118
  # - Creates mappings for each property in the collection items
119
119
  # - Each property gets mapped with array notation and appropriate prefixes
120
120
  #
121
- # @param key_prefix [Array<Symbol>] Prefix for the source key
121
+ # @param key_prefix [Array<String>] Prefix for the source key
122
122
  # @param value_prefix [Array<String>] Prefix for the target value
123
123
  # @param mapping [Hash] The mapping hash to be updated
124
124
  # @param version [String, nil] The version to create mapping for
@@ -17,33 +17,33 @@ module Verquest
17
17
  class Field < Base
18
18
  # List of allowed field types
19
19
  # @return [Array<Symbol>]
20
- ALLOWED_TYPES = %i[string number integer boolean].freeze
20
+ ALLOWED_TYPES = %w[string number integer boolean].freeze
21
21
 
22
22
  # Initialize a new Field property
23
23
  #
24
- # @param name [Symbol] The name of the property
25
- # @param type [Symbol] The data type for this field, must be one of ALLOWED_TYPES
24
+ # @param name [String, Symbol] The name of the property
25
+ # @param type [String, Symbol] The data type for this field, must be one of ALLOWED_TYPES
26
26
  # @param required [Boolean] Whether this property is required
27
27
  # @param map [String, nil] The mapping path for this property
28
28
  # @param schema_options [Hash] Additional JSON schema options for this property
29
29
  # @raise [ArgumentError] If type is not one of the allowed types
30
30
  # @raise [ArgumentError] If attempting to map a field to root without a name
31
31
  def initialize(name:, type:, required: false, map: nil, **schema_options)
32
- raise ArgumentError, "Type must be one of #{ALLOWED_TYPES.join(", ")}" unless ALLOWED_TYPES.include?(type)
32
+ raise ArgumentError, "Type must be one of #{ALLOWED_TYPES.join(", ")}" unless ALLOWED_TYPES.include?(type.to_s)
33
33
  raise ArgumentError, "You can not map fields to the root without a name" if map == "/"
34
34
 
35
- @name = name
36
- @type = type
35
+ @name = name.to_s
36
+ @type = type.to_s
37
37
  @required = required
38
38
  @map = map
39
- @schema_options = schema_options
39
+ @schema_options = schema_options&.transform_keys(&:to_s)
40
40
  end
41
41
 
42
42
  # Generate JSON schema definition for this field
43
43
  #
44
44
  # @return [Hash] The schema definition for this field
45
45
  def to_schema
46
- {name => {type: type}.merge(schema_options)}
46
+ {name => {"type" => type}.merge(schema_options)}
47
47
  end
48
48
 
49
49
  # Create mapping for this field property
@@ -14,17 +14,17 @@ module Verquest
14
14
  class Object < Base
15
15
  # Initialize a new Object property
16
16
  #
17
- # @param name [String] The name of the property
17
+ # @param name [String, Symbol] The name of the property
18
18
  # @param required [Boolean] Whether this property is required
19
19
  # @param map [String, nil] The mapping path for this property
20
20
  # @param schema_options [Hash] Additional JSON schema options for this property
21
21
  def initialize(name:, required: false, map: nil, **schema_options)
22
22
  @properties = {}
23
23
 
24
- @name = name
24
+ @name = name.to_s
25
25
  @required = required
26
26
  @map = map
27
- @schema_options = schema_options
27
+ @schema_options = schema_options&.transform_keys(&:to_s)
28
28
  end
29
29
 
30
30
  # Add a child property to this object
@@ -32,7 +32,7 @@ module Verquest
32
32
  # @param property [Verquest::Properties::Base] The property to add to this object
33
33
  # @return [Verquest::Properties::Base] The added property
34
34
  def add(property)
35
- properties[property.name] = property
35
+ properties[property.name.to_s] = property
36
36
  end
37
37
 
38
38
  # Generate JSON schema definition for this object property
@@ -41,9 +41,9 @@ module Verquest
41
41
  def to_schema
42
42
  {
43
43
  name => {
44
- type: :object,
45
- required: properties.values.select(&:required).map(&:name),
46
- properties: properties.transform_values { |property| property.to_schema[property.name] }
44
+ "type" => "object",
45
+ "required" => properties.values.select(&:required).map(&:name),
46
+ "properties" => properties.transform_values { |property| property.to_schema[property.name] }
47
47
  }.merge(schema_options)
48
48
  }
49
49
  end
@@ -55,16 +55,16 @@ module Verquest
55
55
  def to_validation_schema(version: nil)
56
56
  {
57
57
  name => {
58
- type: :object,
59
- required: properties.values.select(&:required).map(&:name),
60
- properties: properties.transform_values { |property| property.to_validation_schema(version:)[property.name] }
58
+ "type" => "object",
59
+ "required" => properties.values.select(&:required).map(&:name),
60
+ "properties" => properties.transform_values { |property| property.to_validation_schema(version: version)[property.name] }
61
61
  }.merge(schema_options)
62
62
  }
63
63
  end
64
64
 
65
65
  # Create mapping for this object property and all its children
66
66
  #
67
- # @param key_prefix [Array<Symbol>] Prefix for the source key
67
+ # @param key_prefix [Array<String>] Prefix for the source key
68
68
  # @param value_prefix [Array<String>] Prefix for the target value
69
69
  # @param mapping [Hash] The mapping hash to be updated
70
70
  # @param version [String, nil] The version to create mapping for
@@ -23,13 +23,13 @@ module Verquest
23
23
  class Reference < Base
24
24
  # Initialize a new Reference property
25
25
  #
26
- # @param name [String] The name of the property
26
+ # @param name [String, Symbol] The name of the property
27
27
  # @param from [Class] The schema class to reference
28
28
  # @param property [Symbol, nil] Optional specific property to reference
29
29
  # @param map [String, nil] The mapping path for this property
30
30
  # @param required [Boolean] Whether this property is required
31
31
  def initialize(name:, from:, property: nil, map: nil, required: false)
32
- @name = name
32
+ @name = name.to_s
33
33
  @from = from
34
34
  @property = property
35
35
  @map = map
@@ -41,7 +41,7 @@ module Verquest
41
41
  # @return [Hash] The schema definition with a $ref pointer
42
42
  def to_schema
43
43
  {
44
- name => {"$ref": from.to_ref(property:)}
44
+ name => {"$ref" => from.to_ref(property: property)}
45
45
  }
46
46
  end
47
47
 
@@ -58,7 +58,7 @@ module Verquest
58
58
  # Create mapping for this reference property
59
59
  # This delegates to the referenced schema's mapping with appropriate key prefixing
60
60
  #
61
- # @param key_prefix [Array<Symbol>] Prefix for the source key
61
+ # @param key_prefix [Array<String>] Prefix for the source key
62
62
  # @param value_prefix [Array<String>] Prefix for the target value
63
63
  # @param mapping [Hash] The mapping hash to be updated
64
64
  # @param version [String, nil] The version to create mapping for
@@ -113,12 +113,11 @@ module Verquest
113
113
 
114
114
  case data
115
115
  when Hash
116
- # Check if the key exists (as string or symbol)
117
- return nil unless data.key?(key.to_s) || data.key?(key.to_sym)
116
+ # Only check for string keys
117
+ return nil unless data.key?(key.to_s)
118
118
 
119
- # Determine the actual key type used in the hash
120
- actual_key = data.key?(key.to_s) ? key.to_s : key.to_sym
121
- value = data[actual_key]
119
+ # Always use string keys
120
+ value = data[key.to_s]
122
121
 
123
122
  if current_part[:array] && value.is_a?(Array)
124
123
  # Process array elements and filter out nil values
@@ -153,7 +152,7 @@ module Verquest
153
152
 
154
153
  current_part = path_parts.first
155
154
  remaining_path = path_parts[1..]
156
- key = current_part[:key].to_sym # Convert key to symbol for consistent symbol keys
155
+ key = current_part[:key].to_s # Ensure key is a string for consistency
157
156
 
158
157
  if remaining_path.empty?
159
158
  # End of path, set the value directly
@@ -50,7 +50,7 @@ module Verquest
50
50
  # @param name [String] The name/identifier of the version
51
51
  # @return [Version] A new Version instance
52
52
  def initialize(name:)
53
- @name = name
53
+ @name = name.to_s
54
54
  @schema_options = {}
55
55
  @properties = {}
56
56
  end
@@ -69,7 +69,7 @@ module Verquest
69
69
  # @return [Verquest::Properties::Base] The removed property
70
70
  # @raise [PropertyNotFoundError] If the property doesn't exist
71
71
  def remove(property_name)
72
- properties.delete(property_name) || raise(PropertyNotFoundError.new("Property '#{property_name}' is not defined on '#{name}"))
72
+ properties.delete(property_name.to_s) || raise(PropertyNotFoundError.new("Property '#{property_name}' is not defined on '#{name}'"))
73
73
  end
74
74
 
75
75
  # Check if this version has a property with the given name
@@ -77,7 +77,7 @@ module Verquest
77
77
  # @param property_name [Symbol, String] The name of the property to check
78
78
  # @return [Boolean] true if the property exists, false otherwise
79
79
  def has?(property_name)
80
- properties.key?(property_name)
80
+ properties.key?(property_name.to_s)
81
81
  end
82
82
 
83
83
  # Copy properties from another version
@@ -90,7 +90,7 @@ module Verquest
90
90
  raise ArgumentError, "Expected a Verquest::Version instance" unless version.is_a?(Version)
91
91
 
92
92
  version.properties.values.each do |property|
93
- next if exclude_properties.include?(property.name)
93
+ next if exclude_properties.include?(property.name.to_sym)
94
94
 
95
95
  add(property)
96
96
  end
@@ -114,27 +114,30 @@ module Verquest
114
114
  #
115
115
  # @return [Boolean] true if the schema is valid, false otherwise
116
116
  def validate_schema
117
- schema_name = Verquest.configuration.json_schema_version
118
-
119
- metaschema = JSON::Validator.validator_for_name(schema_name).metaschema
120
- JSON::Validator.validate(metaschema, validation_schema)
117
+ JSONSchemer.validate_schema(
118
+ validation_schema,
119
+ meta_schema: Verquest.configuration.json_schema_uri
120
+ )
121
121
  end
122
122
 
123
123
  # Validate request parameters against the version's validation schema
124
124
  #
125
125
  # @param params [Hash] The request parameters to validate
126
- # @param component_reference [String] A reference string for components in the schema
127
- # @param remove_extra_root_keys [Boolean] Whether to remove extra keys not in the schema
128
126
  # @return [Array<Hash>] An array of validation error details, or empty if valid
129
- def validate_params(params:, component_reference:, remove_extra_root_keys:)
130
- schema_name = Verquest.configuration.json_schema_version
131
-
132
- result = JSON::Validator.fully_validate(validation_schema, params, version: schema_name, errors_as_objects: true)
133
- return result if result.empty?
134
-
135
- result.map do |error|
136
- schema = error.delete(:schema)
137
- error[:message].gsub!(schema.to_s, component_reference)
127
+ def validate_params(params:)
128
+ schemer = JSONSchemer.schema(
129
+ validation_schema,
130
+ meta_schema: Verquest.configuration.json_schema_uri,
131
+ insert_property_defaults: Verquest.configuration.insert_property_defaults
132
+ )
133
+
134
+ schemer.validate(params).map do |error|
135
+ {
136
+ pointer: error["data_pointer"],
137
+ type: error["type"],
138
+ message: error["error"],
139
+ details: error["details"]
140
+ }
138
141
  end
139
142
  end
140
143
 
@@ -147,7 +150,7 @@ module Verquest
147
150
  raise PropertyNotFoundError.new("Property '#{property}' is not defined on '#{name}'") unless has?(property)
148
151
 
149
152
  {}.tap do |mapping|
150
- properties[property].mapping(key_prefix: [], value_prefix: [], mapping: mapping, version: name)
153
+ properties[property.to_s].mapping(key_prefix: [], value_prefix: [], mapping: mapping, version: name)
151
154
  end
152
155
  end
153
156
 
@@ -170,10 +173,10 @@ module Verquest
170
173
  # @return [Hash] The frozen schema hash
171
174
  def prepare_schema
172
175
  @schema = {
173
- type: :object,
174
- description: description,
175
- required: properties.values.select(&:required).map(&:name),
176
- properties: properties.transform_values { |property| property.to_schema[property.name] }
176
+ "type" => "object",
177
+ "description" => description,
178
+ "required" => properties.values.select(&:required).map(&:name),
179
+ "properties" => properties.transform_values { |property| property.to_schema[property.name] }
177
180
  }.merge(schema_options).freeze
178
181
  end
179
182
 
@@ -185,10 +188,10 @@ module Verquest
185
188
  # @return [Hash] The frozen validation schema hash
186
189
  def prepare_validation_schema
187
190
  @validation_schema = {
188
- type: :object,
189
- description: description,
190
- required: properties.values.select(&:required).map(&:name),
191
- properties: properties.transform_values { |property| property.to_validation_schema(version: name)[property.name] }
191
+ "type" => "object",
192
+ "description" => description,
193
+ "required" => properties.values.select(&:required).map(&:name),
194
+ "properties" => properties.transform_values { |property| property.to_validation_schema(version: name)[property.name] }
192
195
  }.merge(schema_options).freeze
193
196
  end
194
197
 
data/lib/verquest.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "zeitwerk"
4
- require "json-schema"
4
+ require "json_schemer"
5
5
 
6
6
  loader = Zeitwerk::Loader.new
7
7
  loader.tag = File.basename(__FILE__, ".rb")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: verquest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Petr Hlavicka
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-06-22 00:00:00.000000000 Z
11
+ date: 2025-06-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zeitwerk
@@ -25,19 +25,19 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.7'
27
27
  - !ruby/object:Gem::Dependency
28
- name: json-schema
28
+ name: json_schemer
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '5.0'
33
+ version: '2.4'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '5.0'
40
+ version: '2.4'
41
41
  description: Verquest helps you version API requests, simplifying the management of
42
42
  changes, handling the mapping for internal versus external names and structures,
43
43
  validating parameters, and exporting your requests to JSON Schema components for