Class: Lighthouse::ServiceException

Inherits:
Object
  • Object
show all
Extended by:
SentryLogging
Defined in:
lib/lighthouse/service_exception.rb

Overview

Custom exception that maps Lighthouse API errors to controller ExceptionHandling-friendly format

Constant Summary collapse

ERROR_MAP =

a map of the known Lighthouse errors based on the documentation developer.va.gov/

{
  504 => Common::Exceptions::GatewayTimeout,
  503 => Common::Exceptions::ServiceUnavailable,
  502 => Common::Exceptions::BadGateway,
  500 => Common::Exceptions::ExternalServerInternalServerError,
  429 => Common::Exceptions::TooManyRequests,
  413 => Common::Exceptions::PayloadTooLarge,
  404 => Common::Exceptions::ResourceNotFound,
  403 => Common::Exceptions::Forbidden,
  401 => Common::Exceptions::Unauthorized,
  400 => Common::Exceptions::BadRequest
}.freeze

Class Method Summary collapse

Methods included from SentryLogging

log_exception_to_sentry, log_message_to_sentry, non_nil_hash?, normalize_level, rails_logger

Class Method Details

.error_class(status_code) ⇒ Object

chooses which error class should be reported based on the http status



40
41
42
43
44
# File 'lib/lighthouse/service_exception.rb', line 40

def self.error_class(status_code)
  return Common::Exceptions::ServiceError unless ERROR_MAP.include?(status_code)

  ERROR_MAP[status_code]
end

.error_object_details(error_body, status_code) ⇒ Object

error details that match the evss_errors response schema uses known fields in the Lighthouse errors such as “title”, “code”, “detail”, “message”, “error” used to get more information from Lighthouse errors in the controllers



69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/lighthouse/service_exception.rb', line 69

def self.error_object_details(error_body, status_code)
  status = status_code.to_s
  title = error_body['title'] || error_class(status_code).to_s
  detail = error_body['detail'] ||
           error_body['message'] ||
           error_body['error'] ||
           error_body['error_description'] ||
           'No details provided'
  code = error_body['code'] || status

  [status, title, detail, code]
end

.get_errors_from_response(error, status_code) ⇒ Object

extracts and transforms Lighthouse errors into the evss_errors schema for the controller ExceptionHandling class



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/lighthouse/service_exception.rb', line 48

def self.get_errors_from_response(error, status_code)
  errors = error.response[:body]['errors']

  if errors&.any?
    errors.map do |e|
      status, title, detail, code = error_object_details(e, status_code)

      transform_error_keys(e, status, title, detail, code)
    end
  else
    error_body = error.response[:body]

    status, title, detail, code = error_object_details(error_body, status_code)

    [transform_error_keys(error_body, status, title, detail, code)]
  end
end

.get_status_code(response) ⇒ Object



110
111
112
113
114
# File 'lib/lighthouse/service_exception.rb', line 110

def self.get_status_code(response)
  return response.status if response.respond_to?(:status)

  response[:status] if response.instance_of?(Hash) && response&.key?(:status)
end

.json_response?(response) ⇒ Boolean

Returns:

  • (Boolean)


116
117
118
119
# File 'lib/lighthouse/service_exception.rb', line 116

def self.json_response?(response)
  format = response_type(response)
  format&.include? 'application/json'
end

.response_type(response) ⇒ Object



121
122
123
124
125
# File 'lib/lighthouse/service_exception.rb', line 121

def self.response_type(response)
  return response[:headers]['content-type'] if response[:headers]

  response.headers['content-type'] if response.respond_to?(:headers)
end

.send_error(error, service_name, lighthouse_client_id, url) ⇒ Object

sends error logs to sentry that contains the client id and url that the consumer was trying call raises an error based off of what the response status was formats the Lighthouse exception for the controller ExceptionHandling to report out to the consumer

Raises:



27
28
29
30
31
32
33
34
35
36
37
# File 'lib/lighthouse/service_exception.rb', line 27

def self.send_error(error, service_name, lighthouse_client_id, url)
  send_error_logs(error, service_name, lighthouse_client_id, url)

  response = error.response

  status_code = get_status_code(response)
  return error unless status_code

  errors = get_errors_from_response(error, status_code) if json_response?(response)
  raise error_class(status_code).new(errors:)
end

.send_error_logs(error, service_name, lighthouse_client_id, url) ⇒ Object

sends errors to sentry!



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/lighthouse/service_exception.rb', line 90

def self.send_error_logs(error, service_name, lighthouse_client_id, url)
  base_key_string = "#{lighthouse_client_id} #{url} Lighthouse Error"
  Rails.logger.error(
    error.response,
    base_key_string
  )

  extra_context = Raven.extra_context(
    message: error.message,
    url:,
    client_id: lighthouse_client_id
  )

  tags_context = Raven.tags_context(
    external_service: service_name
  )

  log_exception_to_sentry(error, extra_context, tags_context)
end

.transform_error_keys(error_body, status, title, detail, code) ⇒ Object

transform error hash keys into symbols for controller ExceptionHandling class



83
84
85
86
87
# File 'lib/lighthouse/service_exception.rb', line 83

def self.transform_error_keys(error_body, status, title, detail, code)
  error_body
    .merge({ status:, code:, title:, detail: })
    .transform_keys(&:to_sym)
end