glia-errors 0.5.0 → 0.8.0

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: 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