human_error 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/lib/human_error.rb +21 -19
  3. data/lib/human_error/configuration.rb +27 -7
  4. data/lib/human_error/error.rb +60 -28
  5. data/lib/human_error/errors/authentication_errors/duplicate_authentication_error.rb +8 -8
  6. data/lib/human_error/errors/authentication_errors/invalid_token_error.rb +8 -8
  7. data/lib/human_error/errors/authentication_errors/invalid_username_or_password_error.rb +8 -8
  8. data/lib/human_error/errors/crud_errors/association_error.rb +8 -9
  9. data/lib/human_error/errors/crud_errors/resource_not_found_error.rb +8 -8
  10. data/lib/human_error/errors/crud_errors/resource_persistence_error.rb +8 -8
  11. data/lib/human_error/errors/request_errors/parameter_missing_error.rb +40 -0
  12. data/lib/human_error/errors/request_errors/unpermitted_parameters_error.rb +46 -0
  13. data/lib/human_error/rescuable_resource.rb +30 -47
  14. data/lib/human_error/verifiable_resource.rb +36 -0
  15. data/lib/human_error/version.rb +1 -1
  16. data/spec/lib/human_error/configuration_spec.rb +13 -26
  17. data/spec/lib/human_error/error_spec.rb +135 -1
  18. data/spec/lib/human_error/errors/authentication_errors/duplicate_authentication_error_spec.rb +8 -13
  19. data/spec/lib/human_error/errors/authentication_errors/invalid_token_error_spec.rb +8 -12
  20. data/spec/lib/human_error/errors/authentication_errors/invalid_username_or_password_error_spec.rb +8 -13
  21. data/spec/lib/human_error/errors/crud_errors/association_error_spec.rb +8 -16
  22. data/spec/lib/human_error/errors/crud_errors/resource_not_found_error_spec.rb +9 -17
  23. data/spec/lib/human_error/errors/crud_errors/resource_persistence_error_spec.rb +9 -17
  24. data/spec/lib/human_error/errors/request_errors/parameter_missing_error_spec.rb +55 -0
  25. data/spec/lib/human_error/errors/request_errors/unpermitted_parameters_error_spec.rb +62 -0
  26. data/spec/lib/human_error_spec.rb +4 -57
  27. metadata +26 -12
  28. data/lib/human_error/error_code_directory.rb +0 -20
  29. data/lib/human_error/errors.rb +0 -9
  30. data/lib/human_error/errors/request_error.rb +0 -48
  31. data/lib/human_error/knowledgebase_id_directory.rb +0 -20
  32. data/lib/human_error/verifiable_model.rb +0 -30
  33. data/spec/lib/human_error/errors/request_error_spec.rb +0 -95
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 17aba5f28df14fa69f37785ddb08659985741d9b
4
- data.tar.gz: a39be0f21794151eaebf056663e327b3499b3b91
3
+ metadata.gz: ce3584e03d830added3a0b58d9fa67995aba2b62
4
+ data.tar.gz: ce828a6fd224bc186e2da06ce1c007ea3cbad3fa
5
5
  SHA512:
6
- metadata.gz: 88747c7a2352b0cdd2d7b9867c481f033b987f353b1af78faa649ebfeb6c015dc23fdf2b0b550eb01e63e0710d397549da10857ab72d85395ea28a2ca97bd8ec
7
- data.tar.gz: 1d4b15fbb41d93ed4eb13854d21d39535a7a402ecbbcb66b4fd4c9504ebcd656534efd3ba2081214539d0832bcf0cd5ed3eccfc1350d135a8c29e1ca70b75ce7
6
+ metadata.gz: 2383d7ae1f37c0ae716b39526cd6ade1365f09ffd9eaeb5784957e26f8cfa46e77c1593f64a0afc71c4e93627096d363887b31550125cfdd73be29d8b803ccb5
7
+ data.tar.gz: cb3efadd3dd1f368b5889474b27ca8830bd971470b18c4888589f09bcbddae1877a133f1d903268d6f14647273cf038aeaa1daeb970adc1848d3cfc1c4183209
@@ -1,31 +1,29 @@
1
- require 'human_error/version'
1
+ require 'human_error/configuration'
2
2
  require 'human_error/error'
3
- require 'human_error/errors'
3
+ require 'human_error/errors/authentication_error'
4
+ require 'human_error/errors/authentication_errors/duplicate_authentication_error'
5
+ require 'human_error/errors/authentication_errors/invalid_token_error'
6
+ require 'human_error/errors/authentication_errors/invalid_username_or_password_error'
7
+ require 'human_error/errors/crud_error'
8
+ require 'human_error/errors/crud_errors/association_error'
9
+ require 'human_error/errors/crud_errors/resource_not_found_error'
10
+ require 'human_error/errors/crud_errors/resource_persistence_error'
11
+ require 'human_error/errors/request_errors/parameter_missing_error'
12
+ require 'human_error/errors/request_errors/unpermitted_parameters_error'
4
13
  require 'human_error/rescuable_resource'
5
- require 'human_error/verifiable_model'
14
+ require 'human_error/verifiable_resource'
15
+ require 'human_error/version'
6
16
 
7
17
  class HumanError
8
- attr_accessor :configuration
9
-
10
- def initialize
11
- self.configuration = Configuration.new
12
-
13
- yield configuration if block_given?
14
- end
15
-
16
- def fetch(error_type)
18
+ def self.fetch(error_type)
17
19
  Object.const_get("HumanError::Errors::#{error_type}")
18
20
  end
19
21
 
20
- def build(error_type, overrides = {})
21
- overrides = configuration.to_h.merge(overrides)
22
-
22
+ def self.build(error_type, overrides = {})
23
23
  fetch(error_type).new(overrides)
24
24
  end
25
25
 
26
- def convert(original_error, overrides = {})
27
- overrides = configuration.to_h.merge(overrides)
28
-
26
+ def self.convert(original_error, overrides = {})
29
27
  case original_error.class.name
30
28
  when 'ActiveRecord::InvalidForeignKey'
31
29
  fetch('AssociationError').convert(original_error, overrides)
@@ -34,10 +32,14 @@ class HumanError
34
32
  when 'ActiveRecord::RecordInvalid',
35
33
  'ActiveRecord::RecordNotSaved'
36
34
  fetch('ResourcePersistenceError').convert(original_error, overrides)
35
+ when 'ActionController::ParameterMissing',
36
+ fetch('ParameterMissingError').convert(original_error, overrides)
37
+ when 'ActionController::UnpermittedParameters'
38
+ fetch('UnpermittedParametersError').convert(original_error, overrides)
37
39
  end
38
40
  end
39
41
 
40
- def raise(error_type, **args)
42
+ def self.raise(error_type, **args)
41
43
  Kernel.raise build(error_type, **args)
42
44
  end
43
45
  end
@@ -1,16 +1,36 @@
1
+ require 'singleton'
2
+
1
3
  class HumanError
2
4
  class Configuration
3
- attr_accessor :api_version,
4
- :api_error_documentation_url,
5
- :knowledgebase_url
5
+ include Singleton
6
+
7
+ attr_accessor :url_mappings
8
+
9
+ def external_documentation_urls
10
+ @external_documentation_urls ||= url_mappings['external_documentation_urls']
11
+ end
12
+
13
+ def developer_documentation_urls
14
+ @developer_documentation_urls ||= url_mappings['developer_documentation_urls']
15
+ end
6
16
 
7
17
  def to_h
8
18
  {
9
- knowledgebase_url: knowledgebase_url,
10
- api_error_documentation_url: api_error_documentation_url,
11
- api_version: api_version,
19
+ external_documentation_urls: external_documentation_urls,
20
+ developer_documentation_urls: developer_documentation_urls,
12
21
  }
13
22
  end
23
+
24
+ def url_mappings
25
+ @url_mappings ||= {
26
+ 'external_documentation_urls' => {},
27
+ 'developer_documentation_urls' => {},
28
+ }
29
+ end
30
+ end
31
+
32
+ def configuration
33
+ Configuration.instance
14
34
  end
15
35
 
16
36
  def self.configure
@@ -18,6 +38,6 @@ class HumanError
18
38
  end
19
39
 
20
40
  def self.configuration
21
- @configuration ||= Configuration.new
41
+ Configuration.instance
22
42
  end
23
43
  end
@@ -1,7 +1,6 @@
1
1
  require 'json'
2
2
  require 'human_error/configuration'
3
- require 'human_error/error_code_directory'
4
- require 'human_error/knowledgebase_id_directory'
3
+ require 'human_error/utilities/string'
5
4
 
6
5
  class HumanError
7
6
  module Error
@@ -13,41 +12,80 @@ module Error
13
12
  end
14
13
  end
15
14
 
16
- attr_accessor :api_version,
17
- :api_error_documentation_url,
18
- :knowledgebase_url,
19
- :knowledgebase_article_id,
15
+ attr_accessor :id,
16
+ :external_documentation_url,
17
+ :developer_documentation_url,
18
+ :http_status,
20
19
  :code,
20
+ :title,
21
+ :detail,
22
+ :source,
21
23
  :message
22
24
 
23
25
  def initialize(**args)
24
- self.api_version = configuration.api_version
25
- self.api_error_documentation_url = configuration.api_error_documentation_url
26
- self.knowledgebase_url = configuration.knowledgebase_url
27
-
28
26
  args.each do |variable, value|
29
- send("#{variable}=", value)
27
+ public_send("#{variable}=", value)
30
28
  end
31
29
  end
32
30
 
33
- def code
34
- @code || ErrorCodeDirectory.lookup(self.class.name)
31
+ def as_json(_options = {})
32
+ {
33
+ errors: [
34
+ {
35
+ id: id,
36
+ links: {
37
+ about: external_documentation_url,
38
+ documentation: developer_documentation_url,
39
+ },
40
+ status: http_status,
41
+ code: code,
42
+ title: title,
43
+ detail: detail,
44
+ source: source,
45
+ },
46
+ ],
47
+ }
35
48
  end
36
49
 
37
- def knowledgebase_article_id
38
- @knowledgebase_article_id || KnowledgebaseIdDirectory.lookup(self.class.name)
50
+ def to_json(_options = {})
51
+ JSON.dump(as_json)
39
52
  end
40
53
 
41
- def developer_documentation_uri
42
- "#{api_error_documentation_url}/#{code}?version=#{api_version}"
54
+ def id
55
+ @id ||= SecureRandom.uuid
43
56
  end
44
57
 
45
- def customer_support_uri
46
- "#{knowledgebase_url}/#{knowledgebase_article_id}"
58
+ def external_documentation_url
59
+ @external_documentation_url ||= configuration.external_documentation_urls[code]
47
60
  end
48
61
 
49
- def to_json(_options = {})
50
- JSON.dump(as_json)
62
+ def developer_documentation_url
63
+ @developer_documentation_url ||= configuration.developer_documentation_urls[code]
64
+ end
65
+
66
+ def http_status
67
+ @http_status ||= 500
68
+ end
69
+
70
+ alias_method :status, :http_status
71
+
72
+ def code
73
+ @code ||= HumanError::Utilities::String.
74
+ underscore(self.class.name).
75
+ gsub(%r{\A[^/]+/}, '').
76
+ gsub(%r{/}, '.')
77
+ end
78
+
79
+ def title
80
+ @title ||= self.class.name
81
+ end
82
+
83
+ def detail
84
+ @detail ||= 'The server encountered an error.'
85
+ end
86
+
87
+ def source
88
+ @source ||= {}
51
89
  end
52
90
 
53
91
  def message
@@ -55,13 +93,7 @@ module Error
55
93
  end
56
94
 
57
95
  def to_s
58
- @message || developer_message
59
- rescue NoMethodError
60
- super
61
- end
62
-
63
- def developer_message
64
- fail NoMethodError, 'This method must be implemented in a subclass'
96
+ @message || detail
65
97
  end
66
98
 
67
99
  def self.included(base)
@@ -1,9 +1,9 @@
1
- require 'human_error/errors/request_error'
2
1
  require 'human_error/errors/authentication_error'
3
2
 
4
3
  class HumanError
5
4
  module Errors
6
- class DuplicateAuthenticationError < RequestError
5
+ class DuplicateAuthenticationError < RuntimeError
6
+ include Error
7
7
  include AuthenticationError
8
8
 
9
9
  attr_accessor :provider,
@@ -14,23 +14,23 @@ class DuplicateAuthenticationError < RequestError
14
14
  409
15
15
  end
16
16
 
17
- def developer_message
17
+ def title
18
+ 'Duplicate Authentication'
19
+ end
20
+
21
+ def detail
18
22
  'The authentication you attempted to register has already been registered by ' \
19
23
  'another user. We do not currently support allowing multiple users to be connected ' \
20
24
  'to the same authentication.'
21
25
  end
22
26
 
23
- def developer_details
27
+ def source
24
28
  {
25
29
  'provider' => provider,
26
30
  'provider_user_id' => provider_user_id,
27
31
  'user_id' => user_id,
28
32
  }
29
33
  end
30
-
31
- def friendly_message
32
- "Sorry! Someone else has already registered this #{provider} login."
33
- end
34
34
  end
35
35
  end
36
36
  end
@@ -1,9 +1,9 @@
1
- require 'human_error/errors/request_error'
2
1
  require 'human_error/errors/authentication_error'
3
2
 
4
3
  class HumanError
5
4
  module Errors
6
- class InvalidTokenError < RequestError
5
+ class InvalidTokenError < RuntimeError
6
+ include Error
7
7
  include AuthenticationError
8
8
 
9
9
  attr_accessor :authentication_token
@@ -12,18 +12,18 @@ class InvalidTokenError < RequestError
12
12
  401
13
13
  end
14
14
 
15
- def developer_message
15
+ def title
16
+ 'Invalid Token'
17
+ end
18
+
19
+ def detail
16
20
  'The token you attempted to use for this request is invalid for this resource. ' \
17
21
  'Please double-check and try again.'
18
22
  end
19
23
 
20
- def developer_details
24
+ def source
21
25
  { token: '[FILTERED]' }
22
26
  end
23
-
24
- def friendly_message
25
- 'Sorry! You are not authorized to view this.'
26
- end
27
27
  end
28
28
  end
29
29
  end
@@ -1,9 +1,9 @@
1
- require 'human_error/errors/request_error'
2
1
  require 'human_error/errors/authentication_error'
3
2
 
4
3
  class HumanError
5
4
  module Errors
6
- class InvalidUsernameOrPasswordError < RequestError
5
+ class InvalidUsernameOrPasswordError < RuntimeError
6
+ include Error
7
7
  include AuthenticationError
8
8
 
9
9
  attr_accessor :username
@@ -12,18 +12,18 @@ class InvalidUsernameOrPasswordError < RequestError
12
12
  401
13
13
  end
14
14
 
15
- def developer_message
15
+ def title
16
+ 'Invalid Username/Password'
17
+ end
18
+
19
+ def detail
16
20
  'Either the username or password passed in or this request is invalid. Please ' \
17
21
  'double-check and try again.'
18
22
  end
19
23
 
20
- def developer_details
24
+ def source
21
25
  { username: username, password: '[FILTERED]' }
22
26
  end
23
-
24
- def friendly_message
25
- 'Either your email or password is incorrect. Please double-check and try again.'
26
- end
27
27
  end
28
28
  end
29
29
  end
@@ -1,9 +1,9 @@
1
1
  require 'human_error/errors/crud_error'
2
- require 'human_error/errors/request_error'
3
2
 
4
3
  class HumanError
5
4
  module Errors
6
- class AssociationError < RequestError
5
+ class AssociationError < RuntimeError
6
+ include Error
7
7
  include CrudError
8
8
 
9
9
  attr_accessor :association_name,
@@ -33,22 +33,21 @@ class AssociationError < RequestError
33
33
  422
34
34
  end
35
35
 
36
- def developer_message
36
+ def title
37
+ 'Association Error'
38
+ end
39
+
40
+ def detail
37
41
  "The #{association_name} that you attempted to associate with " \
38
42
  "the #{resource_name} was not valid."
39
43
  end
40
44
 
41
- def developer_details
45
+ def source
42
46
  {
43
47
  resource_name => attributes,
44
48
  "#{association_name} id" => association_id,
45
49
  }
46
50
  end
47
-
48
- def friendly_message
49
- "Sorry! There was a problem when we tried to set the #{association_name} on " \
50
- "that #{resource_name}."
51
- end
52
51
  end
53
52
  end
54
53
  end
@@ -1,9 +1,9 @@
1
1
  require 'human_error/errors/crud_error'
2
- require 'human_error/errors/request_error'
3
2
 
4
3
  class HumanError
5
4
  module Errors
6
- class ResourceNotFoundError < RequestError
5
+ class ResourceNotFoundError < RuntimeError
6
+ include Error
7
7
  include CrudError
8
8
 
9
9
  def self.convert(original_error, overrides = {})
@@ -30,19 +30,19 @@ class ResourceNotFoundError < RequestError
30
30
  404
31
31
  end
32
32
 
33
- def developer_message
33
+ def title
34
+ 'Resource Not Found'
35
+ end
36
+
37
+ def detail
34
38
  "The #{resource_name} you attempted to #{action} for this request is either " \
35
39
  'not authorized for the authenticated user or does not exist.'
36
40
  end
37
41
 
38
- def developer_details
42
+ def source
39
43
  { "#{resource_name_underscored}_id" => resource_id }
40
44
  end
41
45
 
42
- def friendly_message
43
- "Sorry! The #{resource_name} you tried to #{action} does not exist."
44
- end
45
-
46
46
  def action
47
47
  @action || 'access'
48
48
  end
@@ -1,9 +1,9 @@
1
1
  require 'human_error/errors/crud_error'
2
- require 'human_error/errors/request_error'
3
2
 
4
3
  class HumanError
5
4
  module Errors
6
- class ResourcePersistenceError < RequestError
5
+ class ResourcePersistenceError < RuntimeError
6
+ include Error
7
7
  include CrudError
8
8
 
9
9
  attr_accessor :errors,
@@ -29,21 +29,21 @@ class ResourcePersistenceError < RequestError
29
29
  422
30
30
  end
31
31
 
32
- def developer_message
32
+ def title
33
+ 'Resource Persistence Error'
34
+ end
35
+
36
+ def detail
33
37
  "One or more of the attributes on the #{resource_name} you attempted " \
34
38
  "to #{action} is invalid."
35
39
  end
36
40
 
37
- def developer_details
41
+ def source
38
42
  {
39
43
  'errors' => errors,
40
44
  'attributes' => attributes,
41
45
  }
42
46
  end
43
-
44
- def friendly_message
45
- "Sorry! We had a problem when tried to #{action} that #{resource_name}."
46
- end
47
47
  end
48
48
  end
49
49
  end