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 )
Namespace
Methods
D
E
N
R
Class Public methods
new( domain = nil, &block )

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

# 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 ]
  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 Public methods
describe( code )

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'.

# File lib/hoodoo/errors/error_descriptions.rb, line 161
def describe( code )
  @descriptions[ code ]
end
errors_for( domain, &block )

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

# File lib/hoodoo/errors/error_descriptions.rb, line 141
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 )

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

code

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

# File lib/hoodoo/errors/error_descriptions.rb, line 152
def recognised?( code )
  @descriptions.has_key?( code )
end