glia-errors 0.5.0 → 0.8.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: cf61f6be102a1651954298dacfe9e93cfeb27f81ad078e52ec7bf16542bf402b
4
- data.tar.gz: 2c9d1373869e3f9525d9f01116ecff9b5a09396b855c7c8ce1e3d9fc96eb43d2
3
+ metadata.gz: 5c7f5990ad3700b39cf8e730592d7a0e1bb41968015c54c648f341e329679852
4
+ data.tar.gz: 56963475888904d6d252deb42667536caeb1a7ff96c7bbb35d5204395f60723d
5
5
  SHA512:
6
- metadata.gz: ec694ade2f6c374c638832d8ad3a6d67523c218e296901b92560807dae34a29b173edc1eacde316c15c616ec063831886aec324da280b81fed6cc97840c435d4
7
- data.tar.gz: d69081a24657b4647e7146d72c165e68b70698f548e7a0b2f1216ade437161a48d873a74b88adcb18f886f10d7fef4b60e0df589ce12466df707e40c7380d48f
6
+ metadata.gz: 7a09bd918e4be8fb7463523004703cf8d94e1a709f70f545f3b8f1d51384c5ba9a2be31c0a0b633042b9eec610003251b1fceb122d266c667ff18f4789487ef1
7
+ data.tar.gz: 4749bb8358fc6a1dc3f8940ae9ef5424cfdb65bef2361a529ea591890e86a8ec43a1b33207be110e7404c0ae270bd0cb197bfe11d744583ef698cce02cbbc3fe
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.7.2
data/README.md CHANGED
@@ -18,7 +18,18 @@ require 'glia/errors'
18
18
 
19
19
  ### For Glia developers
20
20
 
21
- #### Map from `dry-validation` result
21
+ #### Create Glia error manually
22
+
23
+ 1. Select error from the [error list](https://internal-docs.at.samo.io/glia-errors/elixir/api-reference.html#modules)
24
+ - Documentation is for Elixir, however, the errors are the same and their initiation is very similar
25
+ 2. Initialize the error according to the error documentation
26
+
27
+ Example:
28
+ ```
29
+ glia_error = Glia::Errors::ResourceNotFoundError.new(resource: :engagement)
30
+ ```
31
+
32
+ #### Create Glia error from `dry-validation` result
22
33
 
23
34
  Currently 2 `dry-validation` versions are supported:
24
35
  * `v0` up to `0.13`
@@ -29,11 +40,10 @@ schema = Dry::Validation.Schema do
29
40
  # ...
30
41
  end
31
42
  result = schema.(input)
32
- error = Glia::Errors.from_dry_validation_result(result)
33
- response = error.to_h
43
+ glia_error = Glia::Errors.from_dry_validation_result(result)
34
44
  ```
35
45
 
36
- #### Specifying mapping for custom error message
46
+ #### Create Glia error from `dry-validation` that contains custom errors
37
47
 
38
48
  If you have custom `dry-validation` predicates and error messages you can specify a custom error map.
39
49
  Custom error map takes priority over standard error mapping.
@@ -46,8 +56,15 @@ ERROR_MAP = {
46
56
  Glia::Errors::InvalidFormatError.new(field: field)
47
57
  end
48
58
  }
49
- error = Glia::Errors.from_dry_validation_result(result, ERROR_MAP)
50
- response = error.to_h
59
+ glia_error = Glia::Errors.from_dry_validation_result(result, ERROR_MAP)
60
+ ```
61
+
62
+ #### Convert Glia error to a hash
63
+
64
+ You can use this to convert Glia error to hash, so that later it can be converted to JSON.
65
+
66
+ ```ruby
67
+ glia_error.to_h
51
68
  ```
52
69
 
53
70
  ### For REST API integrators
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.5.0'
8
+ spec.version = '0.8.0'
9
9
  spec.authors = ['Glia TechMovers']
10
10
  spec.email = ['techmovers@glia.com']
11
11
 
data/lib/glia/errors.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require_relative './errors/error'
4
4
  require_relative './errors/error_types'
5
5
  require_relative './errors/client_errors'
6
+ require_relative './errors/server_errors'
6
7
  require_relative './errors/mapper'
7
8
 
8
9
  module Glia
@@ -7,8 +7,8 @@ module Glia
7
7
  def initialize(error_details:, message: nil)
8
8
  super(
9
9
  type: INPUT_VALIDATION_ERROR,
10
- ref: "https://example.com/errors/#{INPUT_VALIDATION_ERROR}.html",
11
- message: message,
10
+ ref: create_ref(INPUT_VALIDATION_ERROR),
11
+ message: message || 'Input is invalid',
12
12
  error_details: error_details
13
13
  )
14
14
  end
@@ -18,8 +18,8 @@ module Glia
18
18
  def initialize(field:, message: nil)
19
19
  super(
20
20
  type: INVALID_NUMBER_ERROR,
21
- ref: "https://example.com/errors/#{INVALID_NUMBER_ERROR}.html",
22
- message: "#{humanize(field)} " + (message || 'is invalid')
21
+ ref: create_ref(INVALID_NUMBER_ERROR),
22
+ message: message || "#{Naming.humanize(field)} value is invalid"
23
23
  )
24
24
  end
25
25
  end
@@ -28,8 +28,8 @@ module Glia
28
28
  def initialize(field:, message: nil)
29
29
  super(
30
30
  type: INVALID_VALUE_ERROR,
31
- ref: "https://example.com/errors/#{INVALID_VALUE_ERROR}.html",
32
- message: "#{humanize(field)} " + (message || 'is invalid')
31
+ ref: create_ref(INVALID_VALUE_ERROR),
32
+ message: message || "#{Naming.humanize(field)} value is invalid"
33
33
  )
34
34
  end
35
35
  end
@@ -38,8 +38,8 @@ module Glia
38
38
  def initialize(field:, message: nil)
39
39
  super(
40
40
  type: INVALID_LENGTH_ERROR,
41
- ref: "https://example.com/errors/#{INVALID_LENGTH_ERROR}.html",
42
- message: "#{humanize(field)} " + (message || 'length is invalid')
41
+ ref: create_ref(INVALID_LENGTH_ERROR),
42
+ message: message || "#{Naming.humanize(field)} length is invalid"
43
43
  )
44
44
  end
45
45
  end
@@ -54,13 +54,34 @@ module Glia
54
54
 
55
55
  def initialize(field:, format: nil, message: nil)
56
56
  default_message =
57
- format ? "has invalid format, required format is #{format}" : 'has invalid format'
57
+ if format
58
+ "has invalid format, required format is #{humanize_format(format)}"
59
+ else
60
+ 'has invalid format'
61
+ end
58
62
  super(
59
63
  type: INVALID_FORMAT_ERROR,
60
- ref: "https://example.com/errors/#{INVALID_FORMAT_ERROR}.html",
61
- message: "#{humanize(field)} " + (message || default_message)
64
+ ref: create_ref(INVALID_FORMAT_ERROR),
65
+ message: message || "#{Naming.humanize(field)} #{default_message}"
62
66
  )
63
67
  end
68
+
69
+ private
70
+
71
+ def humanize_format(format)
72
+ case format
73
+ when Formats::DATE
74
+ 'ISO-8601 date'
75
+ when Formats::TIME
76
+ 'ISO-8601 time'
77
+ when Formats::DATE_TIME
78
+ 'ISO-8601 date and time'
79
+ when Formats::UUID
80
+ 'UUID'
81
+ else
82
+ raise 'Unexpected InvalidFormatError format'
83
+ end
84
+ end
64
85
  end
65
86
 
66
87
  class InvalidTypeError < Error
@@ -76,8 +97,9 @@ module Glia
76
97
  def initialize(field:, type:, message: nil)
77
98
  super(
78
99
  type: INVALID_TYPE_ERROR,
79
- ref: "https://example.com/errors/#{INVALID_TYPE_ERROR}.html",
80
- message: "#{humanize(field)} " + (message || "must be of type #{type}")
100
+ ref: create_ref(INVALID_TYPE_ERROR),
101
+ message: message || "#{Naming.humanize(field)} must be of type #{type}",
102
+ error_details: { type: type }
81
103
  )
82
104
  end
83
105
  end
@@ -86,8 +108,8 @@ module Glia
86
108
  def initialize(field:, message: nil)
87
109
  super(
88
110
  type: MISSING_VALUE_ERROR,
89
- ref: "https://example.com/errors/#{MISSING_VALUE_ERROR}.html",
90
- message: "#{humanize(field)} " + (message || 'is missing')
111
+ ref: create_ref(MISSING_VALUE_ERROR),
112
+ message: message || "#{Naming.humanize(field)} is missing"
91
113
  )
92
114
  end
93
115
  end
@@ -96,18 +118,20 @@ module Glia
96
118
  def initialize(field:, message: nil)
97
119
  super(
98
120
  type: UNKNOWN_ERROR,
99
- ref: "https://example.com/errors/#{UNKNOWN_ERROR}.html",
100
- message: "#{humanize(field)} " + (message || 'validation failed with unknown error')
121
+ ref: create_ref(UNKNOWN_ERROR),
122
+ message: message || "#{Naming.humanize(field)} validation failed with unknown error"
101
123
  )
102
124
  end
103
125
  end
104
126
 
105
127
  class ResourceNotFoundError < Error
106
128
  def initialize(resource:, message: nil)
129
+ assert_snake_case(resource)
130
+
107
131
  super(
108
132
  type: RESOURCE_NOT_FOUND_ERROR,
109
- ref: "https://example.com/errors/#{RESOURCE_NOT_FOUND_ERROR}.html",
110
- message: "#{humanize(resource)} " + (message || 'not found'),
133
+ ref: create_ref(RESOURCE_NOT_FOUND_ERROR),
134
+ message: message || "#{Naming.humanize(resource)} not found",
111
135
  error_details: { resource: resource }
112
136
  )
113
137
  end
@@ -115,10 +139,12 @@ module Glia
115
139
 
116
140
  class NotVerifiedError < Error
117
141
  def initialize(resource:, message: nil)
142
+ assert_snake_case(resource)
143
+
118
144
  super(
119
145
  type: NOT_VERIFIED_ERROR,
120
- ref: "https://example.com/errors/#{NOT_VERIFIED_ERROR}.html",
121
- message: "#{humanize(resource)} " + (message || 'is not verified'),
146
+ ref: create_ref(NOT_VERIFIED_ERROR),
147
+ message: message || "#{Naming.humanize(resource)} is not verified",
122
148
  error_details: { resource: resource }
123
149
  )
124
150
  end
@@ -126,25 +152,30 @@ module Glia
126
152
 
127
153
  class RemainingAssociationError < Error
128
154
  def initialize(resource:, associated_resource:, message: nil)
155
+ assert_snake_case(resource)
156
+ assert_snake_case(associated_resource)
157
+
129
158
  default_message =
130
159
  "cannot be modified/deleted because it is associated to one or more #{
131
- humanize(associated_resource)
160
+ Naming.humanize(associated_resource)
132
161
  }(s)"
133
162
  super(
134
163
  type: REMAINING_ASSOCIATION_ERROR,
135
- ref: "https://example.com/errors/#{REMAINING_ASSOCIATION_ERROR}.html",
136
- message: "#{humanize(resource)} " + (message || default_message),
164
+ ref: create_ref(REMAINING_ASSOCIATION_ERROR),
165
+ message: message || "#{Naming.humanize(resource)} #{default_message}",
137
166
  error_details: { resource: resource, associated_resource: associated_resource }
138
167
  )
139
168
  end
140
169
  end
141
170
 
142
- class LimitExceededError < Error
171
+ class ResourceLimitExceededError < Error
143
172
  def initialize(resource:, max:, message: nil)
173
+ assert_snake_case(resource)
174
+
144
175
  super(
145
176
  type: LIMIT_EXCEEDED_ERROR,
146
- ref: "https://example.com/errors/#{LIMIT_EXCEEDED_ERROR}.html",
147
- message: "#{humanize(resource)} " + (message || "count must not exceed #{max}"),
177
+ ref: create_ref(LIMIT_EXCEEDED_ERROR),
178
+ message: message || "#{Naming.humanize(resource)} count must not exceed #{max}",
148
179
  error_details: { resource: resource, max: max }
149
180
  )
150
181
  end
@@ -152,10 +183,12 @@ module Glia
152
183
 
153
184
  class ResourceAlreadyExistsError < Error
154
185
  def initialize(resource:, message: nil)
186
+ assert_snake_case(resource)
187
+
155
188
  super(
156
189
  type: RESOURCE_ALREADY_EXISTS_ERROR,
157
- ref: "https://example.com/errors/#{RESOURCE_ALREADY_EXISTS_ERROR}.html",
158
- message: "#{humanize(resource)} " + (message || 'already exists'),
190
+ ref: create_ref(RESOURCE_ALREADY_EXISTS_ERROR),
191
+ message: message || "#{Naming.humanize(resource)} already exists",
159
192
  error_details: { resource: resource }
160
193
  )
161
194
  end
@@ -163,10 +196,13 @@ module Glia
163
196
 
164
197
  class InvalidResourceStateError < Error
165
198
  def initialize(resource:, state:, message: nil)
199
+ assert_snake_case(resource)
200
+ assert_snake_case(state)
201
+
166
202
  super(
167
203
  type: INVALID_RESOURCE_STATE_ERROR,
168
- ref: "https://example.com/errors/#{INVALID_RESOURCE_STATE_ERROR}.html",
169
- message: "#{humanize(resource)} " + (message || "is in invalid state: #{state}"),
204
+ ref: create_ref(INVALID_RESOURCE_STATE_ERROR),
205
+ message: message || "#{Naming.humanize(resource)} is in invalid state: #{state}",
170
206
  error_details: { resource: resource, state: state }
171
207
  )
172
208
  end
@@ -176,7 +212,7 @@ module Glia
176
212
  def initialize(message: nil)
177
213
  super(
178
214
  type: AUTHORIZATION_ERROR,
179
- ref: "https://example.com/errors/#{AUTHORIZATION_ERROR}.html",
215
+ ref: create_ref(AUTHORIZATION_ERROR),
180
216
  message: message || 'You do not have permissions to perform the action'
181
217
  )
182
218
  end
@@ -186,11 +222,31 @@ module Glia
186
222
  def initialize(message: nil)
187
223
  super(
188
224
  type: RECIPIENT_OPTED_OUT_ERROR,
189
- ref: "https://example.com/errors/#{RECIPIENT_OPTED_OUT_ERROR}.html",
225
+ ref: create_ref(RECIPIENT_OPTED_OUT_ERROR),
190
226
  message: message || 'Recipient has opted out'
191
227
  )
192
228
  end
193
229
  end
230
+
231
+ class RouteNotFoundError < Error
232
+ def initialize(message: nil)
233
+ super(
234
+ type: ROUTE_NOT_FOUND_ERROR,
235
+ ref: create_ref(ROUTE_NOT_FOUND_ERROR),
236
+ message: message || 'Route not found'
237
+ )
238
+ end
239
+ end
240
+
241
+ class MalformedInputError < Error
242
+ def initialize(message: nil)
243
+ super(
244
+ type: MALFORMED_INPUT_ERROR,
245
+ ref: create_ref(MALFORMED_INPUT_ERROR),
246
+ message: message || 'Request is malformed'
247
+ )
248
+ end
249
+ end
194
250
  # rubocop:enable Style/Documentation
195
251
  end
196
252
  end
@@ -1,9 +1,12 @@
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
9
+ SNAKE_CASE_REGEX = /^[a-z0-9]+(_[a-z0-9]+)*$/.freeze
7
10
  attr_reader :type, :ref, :message, :error_details
8
11
 
9
12
  def initialize(type:, ref:, message: nil, error_details: nil)
@@ -38,13 +41,19 @@ module Glia
38
41
  end
39
42
 
40
43
  def primitive?(details)
41
- details.nil? || [TrueClass, FalseClass, String, Integer, Float].include?(details.class)
44
+ details.nil? ||
45
+ [TrueClass, FalseClass, String, Integer, Float, Symbol].include?(details.class)
46
+ end
47
+
48
+ def assert_snake_case(value)
49
+ return if value.to_s.match(SNAKE_CASE_REGEX)
50
+
51
+ raise ArgumentError, "Expected '#{value}' to be in snake case"
42
52
  end
43
53
 
44
- # Converts from camel_case to capitalized more human readable value
45
- # first_name => "First name"
46
- def humanize(value)
47
- value.to_s.capitalize.gsub('_', ' ')
54
+ def create_ref(type)
55
+ fragment = type.gsub('_', '-')
56
+ "https://docs.glia.com/glia-dev/reference/errors##{fragment}"
48
57
  end
49
58
  end
50
59
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Glia
4
4
  module Errors
5
+ # Client errors
5
6
  INPUT_VALIDATION_ERROR = 'input_validation_error'
6
7
  INVALID_TYPE_ERROR = 'invalid_type_error'
7
8
  INVALID_NUMBER_ERROR = 'invalid_number_error'
@@ -18,5 +19,11 @@ module Glia
18
19
  INVALID_RESOURCE_STATE_ERROR = 'invalid_resource_state_error'
19
20
  AUTHORIZATION_ERROR = 'authorization_error'
20
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
+
25
+ # Server errors
26
+ INTERNAL_SERVER_ERROR = 'internal_server_error'
27
+ SERVICE_UNAVAILABLE_ERROR = 'service_unavailable_error'
21
28
  end
22
29
  end
@@ -0,0 +1,34 @@
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].freeze
17
+ PLURAL_ABBREVIATIONS = %w[ids uuids].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
+ end
33
+ end
34
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Glia
4
+ module Errors
5
+ # rubocop:disable Style/Documentation
6
+ class InternalServerError < Error
7
+ def initialize(message: nil)
8
+ super(
9
+ type: INTERNAL_SERVER_ERROR,
10
+ ref: create_ref(INTERNAL_SERVER_ERROR),
11
+ message: message || 'Internal server error'
12
+ )
13
+ end
14
+ end
15
+
16
+ class ServiceUnavailableError < Error
17
+ def initialize(message: nil)
18
+ super(
19
+ type: SERVICE_UNAVAILABLE_ERROR,
20
+ ref: create_ref(SERVICE_UNAVAILABLE_ERROR),
21
+ message: message || 'Service unavailable'
22
+ )
23
+ end
24
+ end
25
+ # rubocop:enable Style/Documentation
26
+ end
27
+ 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.5.0
4
+ version: 0.8.0
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-02-22 00:00:00.000000000 Z
11
+ date: 2021-03-12 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: ''
14
14
  email:
@@ -22,6 +22,7 @@ files:
22
22
  - ".prettierrc"
23
23
  - ".rspec"
24
24
  - ".rubocop.yml"
25
+ - ".ruby-version"
25
26
  - ".travis.yml"
26
27
  - Appraisals
27
28
  - Gemfile
@@ -36,6 +37,8 @@ files:
36
37
  - lib/glia/errors/error.rb
37
38
  - lib/glia/errors/error_types.rb
38
39
  - lib/glia/errors/mapper.rb
40
+ - lib/glia/errors/naming.rb
41
+ - lib/glia/errors/server_errors.rb
39
42
  homepage:
40
43
  licenses:
41
44
  - MIT
@@ -55,7 +58,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
55
58
  - !ruby/object:Gem::Version
56
59
  version: '0'
57
60
  requirements: []
58
- rubygems_version: 3.0.6
61
+ rubygems_version: 3.1.4
59
62
  signing_key:
60
63
  specification_version: 4
61
64
  summary: Glia REST API errors