Class: Hoodoo::ErrorDescriptions

Inherits:
Object
  • Object
show all
Defined in:
lib/hoodoo/errors/error_descriptions.rb

Overview

A collection of error descriptions. API service implementations create one of these, which self-declares platform and generic error domain codes. A simple DSL is available to declare service-specific errors. Since the middleware is responsible for instantiating an error collection inside a response object which service implementations use to signal error conditions, the service’s interface class uses the interface description DSL to call through to here behind the scenes; for example:

class TransactionImplementation < Hoodoo::Services::Implementation
  # ...
end

class TransactionInterface < Hoodoo::Services::Interface
  interface :Transaction do
    endpoint :transactions, TransactionImplementation
    errors_for 'transaction' do
      error 'duplicate_transaction', status: 409, message: 'Duplicate transaction', :required => [ :client_uid ]
    end
  end
end

The #errors_for method takes the domain of the error as a string - the part that comes before the “.” in error codes. Then a series of error calls describe the individual error codes. See Hoodoo::ErrorDescriptions::DomainDescriptions#error for details.

An instance of the Hoodoo::ErrorDescriptions class gets built behind the scenes as part of the service interface description. This is found by the middleware and passed to a Hoodoo::Errors constructor. The result is stored in a Hoodoo::Services::Response instance and passed to handler methods in the service’s Hoodoo::Services::Implementation subclass for each request. Service implementations access the errors collection through Hoodoo::Services::Response#errors and can then add errors using the generic or platform domains, or whatever additional custom domain(s) they defined in the service interface subclass.

For direct callers (e.g. the middleware), there is a shorthand form to invoke the DSL where the constructor is used in the same way as #errors_for:

ERROR_DESCRIPTIONS = Hoodoo::ErrorDescriptions.new( 'transaction' ) do
  error 'duplicate_transaction', status: 409, message: 'Duplicate transaction', :required => [ :client_uid ]
end

Either way,

As per the example above, services can share an instance across requests (and threads) via a class’s variable if the descriptions don’t change. You would use the descriptions to inform a Hoodoo::Errors instance of the available codes and their requirements:

@errors = Hoodoo::Errors.new( ERROR_DESCRIPTIONS )

Defined Under Namespace

Classes: DomainDescriptions

Instance Method Summary collapse

Constructor Details

#initialize(domain = nil, &block) ⇒ ErrorDescriptions

Create an instance, self-declaring platform and generic domain errors. You can optionally call the constructor with an error domain and code block, to declare errors all in one go rather than making a separate call to #errors_for (but both approaches are valid).

domain

Optional domain, just as used in #errors_for

&block

Optional block, just as used in #errors_for



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/hoodoo/errors/error_descriptions.rb', line 80

def initialize( domain = nil, &block )

  @descriptions = {}

  # Up to date at Preview Release 9, 2014-11-10.

  errors_for 'platform' do
    error 'not_found',              status: 404, message: 'Not found',                    reference: [ :entity_name ]
    error 'malformed',              status: 422, message: 'Malformed request'
    error 'invalid_session',        status: 401, message: 'Invalid session'
    error 'forbidden',              status: 403, message: 'Action not authorized'
    error 'method_not_allowed',     status: 405, message: 'Method not allowed'
    error 'timeout',                status: 408, message: 'Request timeout'
    error 'fault',                  status: 500, message: 'Internal error',               reference: [ :exception ]
    error 'downstream_error',       status: 500, message: 'downstream error',             reference: [ :downstream_system, :message, :http_code, :platform_uuid, :url ]
  end

  # Up to date at Preview Release 9, 2014-11-10.

  errors_for 'generic' do
    error 'not_found',              status: 404, message: 'Resource not found',            reference: [ :ident ]
    error 'contemporary_exists',    status: 404, message: 'Contemporary record exists',    reference: [ :ident ]
    error 'malformed',              status: 422, message: 'Malformed payload'
    error 'required_field_missing', status: 422, message: 'Required field missing',        reference: [ :field_name ]
    error 'invalid_string',         status: 422, message: 'Invalid string format',         reference: [ :field_name ]
    error 'invalid_integer',        status: 422, message: 'Invalid integer format',        reference: [ :field_name ]
    error 'invalid_float',          status: 422, message: 'Invalid float format',          reference: [ :field_name ]
    error 'invalid_decimal',        status: 422, message: 'Invalid decimal format',        reference: [ :field_name ]
    error 'invalid_boolean',        status: 422, message: 'Invalid boolean format',        reference: [ :field_name ]
    error 'invalid_enum',           status: 422, message: 'Invalid enumeration',           reference: [ :field_name ]
    error 'invalid_date',           status: 422, message: 'Invalid date specifier',        reference: [ :field_name ]
    error 'invalid_time',           status: 422, message: 'Invalid time specifier',        reference: [ :field_name ]
    error 'invalid_datetime',       status: 422, message: 'Invalid date-time specifier',   reference: [ :field_name ]
    error 'invalid_uuid',           status: 422, message: 'Invalid UUID',                  reference: [ :field_name ]
    error 'invalid_array',          status: 422, message: 'Invalid array',                 reference: [ :field_name ]
    error 'invalid_object',         status: 422, message: 'Invalid object',                reference: [ :field_name ]
    error 'invalid_hash',           status: 422, message: 'Invalid hash',                  reference: [ :field_name ]
    error 'invalid_duplication',    status: 422, message: 'Duplicates not allowed',        reference: [ :field_name ]
    error 'invalid_state',          status: 422, message: 'State transition not allowed',  reference: [ :destination_state ]
    error 'invalid_parameters',     status: 422, message: 'Invalid parameters'
    error 'mutually_exclusive',     status: 422, message: 'Mutually exclusive parameters', reference: [ :field_names ]
  end

  # Add caller's custom errors for the shorthand form, if provided.

  if ( domain != nil && domain != '' && block_given?() )
    errors_for( domain, &block )
  end
end

Instance Method Details

#describe(code) ⇒ Object

Return the options description hash, as passed to error calls in the block given to #errors_for, for the given code.

code

Error code in full, e.g. +generic.invalid_state’.



162
163
164
# File 'lib/hoodoo/errors/error_descriptions.rb', line 162

def describe( code )
  @descriptions[ code ]
end

#errors_for(domain, &block) ⇒ Object

Implement the collection’s part of the small DSL used for error declaration. Call here, passing the error domain (usually the singular service name or resource name, e.g. “transaction” and defined by the part of the platform API the service is implementing) and a block. The block makes one or more “error” calls, which actually end up calling Hoodoo::ErrorDescriptions::DomainDescriptions#error behind the scenes.

See the implementation of #initialize for a worked example.

domain

Error domain, e.g. platform, transaction

&block

Block which makes one or more calls to “error



142
143
144
145
146
147
# File 'lib/hoodoo/errors/error_descriptions.rb', line 142

def errors_for( domain, &block )
  domain_descriptions = Hoodoo::ErrorDescriptions::DomainDescriptions.new( domain )
  domain_descriptions.instance_eval( &block )

  @descriptions.merge!( domain_descriptions.descriptions )
end

#recognised?(code) ⇒ Boolean

Is the given error code recognised? Returns true if so, else false.

code

Error code in full, e.g. +generic.invalid_state’.

Returns:

  • (Boolean)


153
154
155
# File 'lib/hoodoo/errors/error_descriptions.rb', line 153

def recognised?( code )
  @descriptions.has_key?( code )
end