glia-errors 0.7.0 → 0.11.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f938565ae0608918f0808c950e1d2621f7d8ef2d347cb9146a37fc1af461a519
4
- data.tar.gz: 7d8d9672987fe83c77884532e052adee18e3e980462176b6482dd1a41fb755ec
3
+ metadata.gz: c39d2869c04082f96dec69d927b471a4ea9a94444cd1b1fefa27c1927599f6d6
4
+ data.tar.gz: f7858bf6b262b96e3dbd8c2463c6d62c299d9adb6a911b91cb0aa2c814196bdc
5
5
  SHA512:
6
- metadata.gz: f09300cb765f7ce0fe8d57cce7f8259303acd5dec9ffd61a36307ba0afb9d89c17ca95eb8010526a442ab0028da8fc9c61821f7fbe3cd5727c5d0df2a33e3821
7
- data.tar.gz: 8208ee1f6c9e00975df486a1d8fb3f1457f38a576970f15485191f9639340b0ff5247dbcf527f2474ef1f0696ff519994985e9917c91949c33c9e6bcbc9a3c42
6
+ metadata.gz: 2e01e99725306a950aa584ca37c00535f8a9bdcf1194e01961e325eb24393010df7afefadcd8e681536cc23c4594afec98e5622f4650b15c216a9e80ecce9149
7
+ data.tar.gz: 0626d5fc71db27e69180411f3bf77fb436357d1ff3b12019646115cf09f129edabd0faf40a0d8b704c023739f804e4b07de61768f852a8221d35385e04c16335
data/glia-errors.gemspec CHANGED
@@ -5,7 +5,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = 'glia-errors'
8
- spec.version = '0.7.0'
8
+ spec.version = '0.11.1'
9
9
  spec.authors = ['Glia TechMovers']
10
10
  spec.email = ['techmovers@glia.com']
11
11
 
data/lib/glia/errors.rb CHANGED
@@ -12,7 +12,7 @@ module Glia
12
12
  def self.from_dry_validation_result(result, custom_error_map = {})
13
13
  dry_validation_version = Gem.loaded_specs['dry-validation'].version
14
14
  if dry_validation_version < Gem::Version.new('1.0')
15
- Mapper.from_dry_validation_result(result.output, result.messages, custom_error_map)
15
+ Mapper.from_dry_validation_result(result.output, result.errors, custom_error_map)
16
16
  elsif dry_validation_version <= Gem::Version.new('1.6')
17
17
  Mapper.from_dry_validation_result(result.to_h, result.errors.to_h, custom_error_map)
18
18
  else
@@ -5,6 +5,12 @@ module Glia
5
5
  # rubocop:disable Style/Documentation
6
6
  class InputValidationError < Error
7
7
  def initialize(error_details:, message: nil)
8
+ raise ArgumentError, 'At least 1 error detail is required' if error_details.keys.count.zero?
9
+
10
+ error_details.each_value do |value|
11
+ raise ArgumentError, 'error_details values must be lists' unless value.is_a?(Array)
12
+ end
13
+
8
14
  super(
9
15
  type: INPUT_VALIDATION_ERROR,
10
16
  ref: create_ref(INPUT_VALIDATION_ERROR),
@@ -19,7 +25,7 @@ module Glia
19
25
  super(
20
26
  type: INVALID_NUMBER_ERROR,
21
27
  ref: create_ref(INVALID_NUMBER_ERROR),
22
- message: message || "#{humanize(field)} value is invalid"
28
+ message: message || "#{Naming.humanize(field)} value is invalid"
23
29
  )
24
30
  end
25
31
  end
@@ -29,7 +35,7 @@ module Glia
29
35
  super(
30
36
  type: INVALID_VALUE_ERROR,
31
37
  ref: create_ref(INVALID_VALUE_ERROR),
32
- message: message || "#{humanize(field)} value is invalid"
38
+ message: message || "#{Naming.humanize(field)} value is invalid"
33
39
  )
34
40
  end
35
41
  end
@@ -39,7 +45,7 @@ module Glia
39
45
  super(
40
46
  type: INVALID_LENGTH_ERROR,
41
47
  ref: create_ref(INVALID_LENGTH_ERROR),
42
- message: message || "#{humanize(field)} length is invalid"
48
+ message: message || "#{Naming.humanize(field)} length is invalid"
43
49
  )
44
50
  end
45
51
  end
@@ -54,13 +60,34 @@ module Glia
54
60
 
55
61
  def initialize(field:, format: nil, message: nil)
56
62
  default_message =
57
- format ? "has invalid format, required format is #{format}" : 'has invalid format'
63
+ if format
64
+ "has invalid format, required format is #{humanize_format(format)}"
65
+ else
66
+ 'has invalid format'
67
+ end
58
68
  super(
59
69
  type: INVALID_FORMAT_ERROR,
60
70
  ref: create_ref(INVALID_FORMAT_ERROR),
61
- message: message || "#{humanize(field)} #{default_message}"
71
+ message: message || "#{Naming.humanize(field)} #{default_message}"
62
72
  )
63
73
  end
74
+
75
+ private
76
+
77
+ def humanize_format(format)
78
+ case format
79
+ when Formats::DATE
80
+ 'ISO-8601 date'
81
+ when Formats::TIME
82
+ 'ISO-8601 time'
83
+ when Formats::DATE_TIME
84
+ 'ISO-8601 date and time'
85
+ when Formats::UUID
86
+ 'UUID'
87
+ else
88
+ raise 'Unexpected InvalidFormatError format'
89
+ end
90
+ end
64
91
  end
65
92
 
66
93
  class InvalidTypeError < Error
@@ -77,7 +104,7 @@ module Glia
77
104
  super(
78
105
  type: INVALID_TYPE_ERROR,
79
106
  ref: create_ref(INVALID_TYPE_ERROR),
80
- message: message || "#{humanize(field)} must be of type #{type}",
107
+ message: message || "#{Naming.humanize(field)} must be of type #{type}",
81
108
  error_details: { type: type }
82
109
  )
83
110
  end
@@ -88,29 +115,34 @@ module Glia
88
115
  super(
89
116
  type: MISSING_VALUE_ERROR,
90
117
  ref: create_ref(MISSING_VALUE_ERROR),
91
- message: message || "#{humanize(field)} is missing"
118
+ message: message || "#{Naming.humanize(field)} is missing"
92
119
  )
93
120
  end
94
121
  end
95
122
 
96
123
  class UnknownError < Error
97
- def initialize(field:, message: nil)
124
+ def initialize(field: nil, message: nil)
98
125
  super(
99
126
  type: UNKNOWN_ERROR,
100
127
  ref: create_ref(UNKNOWN_ERROR),
101
- message: message || "#{humanize(field)} validation failed with unknown error"
128
+ message:
129
+ if field
130
+ message || "#{Naming.humanize(field)} validation failed with unknown error"
131
+ else
132
+ message || 'Failed with unknown error'
133
+ end
102
134
  )
103
135
  end
104
136
  end
105
137
 
106
138
  class ResourceNotFoundError < Error
107
139
  def initialize(resource:, message: nil)
108
- assert_snake_case(resource)
140
+ Naming.assert_snake_case(resource)
109
141
 
110
142
  super(
111
143
  type: RESOURCE_NOT_FOUND_ERROR,
112
144
  ref: create_ref(RESOURCE_NOT_FOUND_ERROR),
113
- message: message || "#{humanize(resource)} not found",
145
+ message: message || "#{Naming.humanize(resource)} not found",
114
146
  error_details: { resource: resource }
115
147
  )
116
148
  end
@@ -118,12 +150,12 @@ module Glia
118
150
 
119
151
  class NotVerifiedError < Error
120
152
  def initialize(resource:, message: nil)
121
- assert_snake_case(resource)
153
+ Naming.assert_snake_case(resource)
122
154
 
123
155
  super(
124
156
  type: NOT_VERIFIED_ERROR,
125
157
  ref: create_ref(NOT_VERIFIED_ERROR),
126
- message: message || "#{humanize(resource)} is not verified",
158
+ message: message || "#{Naming.humanize(resource)} is not verified",
127
159
  error_details: { resource: resource }
128
160
  )
129
161
  end
@@ -131,30 +163,30 @@ module Glia
131
163
 
132
164
  class RemainingAssociationError < Error
133
165
  def initialize(resource:, associated_resource:, message: nil)
134
- assert_snake_case(resource)
135
- assert_snake_case(associated_resource)
166
+ Naming.assert_snake_case(resource)
167
+ Naming.assert_snake_case(associated_resource)
136
168
 
137
169
  default_message =
138
170
  "cannot be modified/deleted because it is associated to one or more #{
139
- humanize(associated_resource)
171
+ Naming.humanize(associated_resource)
140
172
  }(s)"
141
173
  super(
142
174
  type: REMAINING_ASSOCIATION_ERROR,
143
175
  ref: create_ref(REMAINING_ASSOCIATION_ERROR),
144
- message: message || "#{humanize(resource)} #{default_message}",
176
+ message: message || "#{Naming.humanize(resource)} #{default_message}",
145
177
  error_details: { resource: resource, associated_resource: associated_resource }
146
178
  )
147
179
  end
148
180
  end
149
181
 
150
- class LimitExceededError < Error
182
+ class ResourceLimitExceededError < Error
151
183
  def initialize(resource:, max:, message: nil)
152
- assert_snake_case(resource)
184
+ Naming.assert_snake_case(resource)
153
185
 
154
186
  super(
155
187
  type: LIMIT_EXCEEDED_ERROR,
156
188
  ref: create_ref(LIMIT_EXCEEDED_ERROR),
157
- message: message || "#{humanize(resource)} count must not exceed #{max}",
189
+ message: message || "#{Naming.humanize(resource)} count must not exceed #{max}",
158
190
  error_details: { resource: resource, max: max }
159
191
  )
160
192
  end
@@ -162,12 +194,12 @@ module Glia
162
194
 
163
195
  class ResourceAlreadyExistsError < Error
164
196
  def initialize(resource:, message: nil)
165
- assert_snake_case(resource)
197
+ Naming.assert_snake_case(resource)
166
198
 
167
199
  super(
168
200
  type: RESOURCE_ALREADY_EXISTS_ERROR,
169
201
  ref: create_ref(RESOURCE_ALREADY_EXISTS_ERROR),
170
- message: message || "#{humanize(resource)} already exists",
202
+ message: message || "#{Naming.humanize(resource)} already exists",
171
203
  error_details: { resource: resource }
172
204
  )
173
205
  end
@@ -175,13 +207,13 @@ module Glia
175
207
 
176
208
  class InvalidResourceStateError < Error
177
209
  def initialize(resource:, state:, message: nil)
178
- assert_snake_case(resource)
179
- assert_snake_case(state)
210
+ Naming.assert_snake_case(resource)
211
+ Naming.assert_snake_case(state)
180
212
 
181
213
  super(
182
214
  type: INVALID_RESOURCE_STATE_ERROR,
183
215
  ref: create_ref(INVALID_RESOURCE_STATE_ERROR),
184
- message: message || "#{humanize(resource)} is in invalid state: #{state}",
216
+ message: message || "#{Naming.humanize(resource)} is in invalid state: #{state}",
185
217
  error_details: { resource: resource, state: state }
186
218
  )
187
219
  end
@@ -206,6 +238,115 @@ module Glia
206
238
  )
207
239
  end
208
240
  end
241
+
242
+ class RouteNotFoundError < Error
243
+ def initialize(message: nil)
244
+ super(
245
+ type: ROUTE_NOT_FOUND_ERROR,
246
+ ref: create_ref(ROUTE_NOT_FOUND_ERROR),
247
+ message: message || 'Route not found'
248
+ )
249
+ end
250
+ end
251
+
252
+ class MalformedInputError < Error
253
+ def initialize(message: nil)
254
+ super(
255
+ type: MALFORMED_INPUT_ERROR,
256
+ ref: create_ref(MALFORMED_INPUT_ERROR),
257
+ message: message || 'Request is malformed'
258
+ )
259
+ end
260
+ end
261
+
262
+ class CarrierError < Error
263
+ def initialize(message: nil)
264
+ super(
265
+ type: CARRIER_ERROR,
266
+ ref: create_ref(CARRIER_ERROR),
267
+ message: message || 'Downstream carrier issue occurred'
268
+ )
269
+ end
270
+ end
271
+
272
+ class GeographicPermissionError < Error
273
+ def initialize(message: nil)
274
+ super(
275
+ type: GEOGRAPHIC_PERMISSION_ERROR,
276
+ ref: create_ref(GEOGRAPHIC_PERMISSION_ERROR),
277
+ message: message || 'Insufficient permissions for geographic region'
278
+ )
279
+ end
280
+ end
281
+
282
+ class MessageBlockedError < Error
283
+ def initialize(message: nil)
284
+ super(
285
+ type: MESSAGE_BLOCKED_ERROR,
286
+ ref: create_ref(MESSAGE_BLOCKED_ERROR),
287
+ message: message || 'Message blocked or filtered'
288
+ )
289
+ end
290
+ end
291
+
292
+ class TelephonyProviderRateLimitExceededError < Error
293
+ def initialize(message: nil)
294
+ super(
295
+ type: TELEPHONY_PROVIDER_RATE_LIMIT_EXCEEDED_ERROR,
296
+ ref: create_ref(TELEPHONY_PROVIDER_RATE_LIMIT_EXCEEDED_ERROR),
297
+ message: message || 'Telephony provider message send rate limit exceeded'
298
+ )
299
+ end
300
+ end
301
+
302
+ class TelephonyProviderQueueLimitExceededError < Error
303
+ def initialize(message: nil)
304
+ super(
305
+ type: TELEPHONY_PROVIDER_QUEUE_LIMIT_EXCEEDED_ERROR,
306
+ ref: create_ref(TELEPHONY_PROVIDER_QUEUE_LIMIT_EXCEEDED_ERROR),
307
+ message: message || 'Telephony provider message send queue is full'
308
+ )
309
+ end
310
+ end
311
+
312
+ class TwilioMessagingServiceConfigurationError < Error
313
+ def initialize(message: nil)
314
+ super(
315
+ type: TWILIO_MESSAGING_SERVICE_CONFIGURATION_ERROR,
316
+ ref: create_ref(TWILIO_MESSAGING_SERVICE_CONFIGURATION_ERROR),
317
+ message: message || 'Invalid Twilio Messaging Service configuration'
318
+ )
319
+ end
320
+ end
321
+
322
+ class UnreachableDestinationError < Error
323
+ def initialize(message: nil)
324
+ super(
325
+ type: UNREACHABLE_DESTINATION_ERROR,
326
+ ref: create_ref(UNREACHABLE_DESTINATION_ERROR),
327
+ message: message || 'Destination is unreachable'
328
+ )
329
+ end
330
+ end
331
+
332
+ class HeadersValidationError < Error
333
+ def initialize(error_details:, message: nil)
334
+ raise ArgumentError, 'At least 1 error detail is required' if error_details.keys.count.zero?
335
+
336
+ error_details.each_value do |value|
337
+ raise ArgumentError, 'error_details values must be lists' unless value.is_a?(Array)
338
+ end
339
+
340
+ error_details.each_key { |key| Naming.assert_header(key) }
341
+
342
+ super(
343
+ type: HEADERS_VALIDATION_ERROR,
344
+ ref: create_ref(HEADERS_VALIDATION_ERROR),
345
+ message: message || 'Headers are invalid',
346
+ error_details: error_details
347
+ )
348
+ end
349
+ end
209
350
  # rubocop:enable Style/Documentation
210
351
  end
211
352
  end
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative './naming'
4
+
3
5
  module Glia
4
6
  module Errors
5
7
  # Base error
6
8
  class Error
7
- SNAKE_CASE_REGEX = /^[a-z0-9]+(_[a-z0-9]+)*$/.freeze
8
9
  attr_reader :type, :ref, :message, :error_details
9
10
 
10
11
  def initialize(type:, ref:, message: nil, error_details: nil)
@@ -43,18 +44,6 @@ module Glia
43
44
  [TrueClass, FalseClass, String, Integer, Float, Symbol].include?(details.class)
44
45
  end
45
46
 
46
- # Converts from camel_case to capitalized more human readable value
47
- # first_name => "First name"
48
- def humanize(value)
49
- value.to_s.capitalize.gsub('_', ' ')
50
- end
51
-
52
- def assert_snake_case(value)
53
- return if value.to_s.match(SNAKE_CASE_REGEX)
54
-
55
- raise ArgumentError, "Expected '#{value}' to be in snake case"
56
- end
57
-
58
47
  def create_ref(type)
59
48
  fragment = type.gsub('_', '-')
60
49
  "https://docs.glia.com/glia-dev/reference/errors##{fragment}"
@@ -19,6 +19,16 @@ module Glia
19
19
  INVALID_RESOURCE_STATE_ERROR = 'invalid_resource_state_error'
20
20
  AUTHORIZATION_ERROR = 'authorization_error'
21
21
  RECIPIENT_OPTED_OUT_ERROR = 'recipient_opted_out_error'
22
+ ROUTE_NOT_FOUND_ERROR = 'route_not_found_error'
23
+ MALFORMED_INPUT_ERROR = 'malformed_input_error'
24
+ CARRIER_ERROR = 'carrier_error'
25
+ GEOGRAPHIC_PERMISSION_ERROR = 'geographic_permission_error'
26
+ MESSAGE_BLOCKED_ERROR = 'message_blocked_error'
27
+ TELEPHONY_PROVIDER_RATE_LIMIT_EXCEEDED_ERROR = 'telephony_provider_rate_limit_exceeded_error'
28
+ TELEPHONY_PROVIDER_QUEUE_LIMIT_EXCEEDED_ERROR = 'telephony_provider_queue_limit_exceeded_error'
29
+ TWILIO_MESSAGING_SERVICE_CONFIGURATION_ERROR = 'twilio_messaging_service_configuration_error'
30
+ UNREACHABLE_DESTINATION_ERROR = 'unreachable_destination_error'
31
+ HEADERS_VALIDATION_ERROR = 'headers_validation_error'
22
32
 
23
33
  # Server errors
24
34
  INTERNAL_SERVER_ERROR = 'internal_server_error'
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Glia
4
+ module Errors
5
+ # Utilities for variable and resouce names
6
+ module Naming
7
+ # Converts from camel_case to more human readable value
8
+ # first_name => "First name"
9
+ # site_id => "Site ID"
10
+ def self.humanize(value)
11
+ result = value.to_s.split('_').map { |word| upcase_if_abbreviation(word) }.join(' ')
12
+
13
+ upcase_first(result)
14
+ end
15
+
16
+ ABBREVIATIONS = %w[id uuid saml sip sms mms uri url].freeze
17
+ PLURAL_ABBREVIATIONS = %w[ids uuids uris urls].freeze
18
+
19
+ private_class_method def self.upcase_if_abbreviation(value)
20
+ if ABBREVIATIONS.include?(value)
21
+ value.upcase
22
+ elsif PLURAL_ABBREVIATIONS.include?(value)
23
+ value[0..-2].upcase.concat('s')
24
+ else
25
+ value
26
+ end
27
+ end
28
+
29
+ private_class_method def self.upcase_first(value)
30
+ value[0].upcase.concat(value[1..-1])
31
+ end
32
+
33
+ SNAKE_CASE_REGEX = /\A[a-z0-9]+(_[a-z0-9]+)*\z/.freeze
34
+
35
+ def self.assert_snake_case(value)
36
+ return if value.to_s.match(SNAKE_CASE_REGEX)
37
+
38
+ raise ArgumentError, "Expected '#{value}' to be in snake case"
39
+ end
40
+
41
+ HEADER_REGEX = /\A[A-Z0-9]+[a-z0-9]*(-[A-Z0-9]+[a-zz0-9]*)*\z/.freeze
42
+
43
+ def self.assert_header(value)
44
+ return if value.to_s.match(HEADER_REGEX)
45
+
46
+ raise ArgumentError, "Expected '#{value}' to be a valid header"
47
+ end
48
+ end
49
+ end
50
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glia-errors
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.11.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Glia TechMovers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-05 00:00:00.000000000 Z
11
+ date: 2021-05-31 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: ''
14
14
  email:
@@ -37,6 +37,7 @@ files:
37
37
  - lib/glia/errors/error.rb
38
38
  - lib/glia/errors/error_types.rb
39
39
  - lib/glia/errors/mapper.rb
40
+ - lib/glia/errors/naming.rb
40
41
  - lib/glia/errors/server_errors.rb
41
42
  homepage:
42
43
  licenses: