Class: Stitches::Errors

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/stitches/errors.rb

Overview

A container for error messages you intend to send as a response to an API request. The canonical error format is a list of all errors that occured, with each error consistent of a code (useful for programmatic logic based on error condition) and a message (useful for displaying to either a log or a human, as documented by the API).

The general usage of this is:

type.json do
  render json: {
      errors: Stitches::Errors.new([
        Stitches::Error.new(code: "name_required", message: "The name is required")
        Stitches::Error.new(code: "numeric_age", message: "The age should be a number")
      ])
    },
    status: 404
end

More likely, you will create these from an exception or from an ActiveRecord::Base.

Exceptions

If you create exceptions for the various known errors in your app, you can rely on the logic in from_exception to generate your code and message.

rescue BadPaymentTypeError => ex
  Stitches::Errors.from_exception(ex)
end

This will create an errors array with one element, which is an error with code “bad_payment_type” and the message of whatever the exception message was.

So, by judicious use and naming of your exceptions, you could do something like this in your controller:

rescue_from MyAppSpecificExceptionBase do |ex|
  render json: { errors: Stitches::Errors.from_exception(ex) }, status: 400
end

And the codes will match the hierarchy of exceptions inheriting from MyAppSpecificExceptionBase.

ActiveRecord

You can also create errors from an ActiveRecord object:

person = Person.create(params)
if person.valid?
  render json: { person: person }, status: 201
else
  render json: { errors: Stitches::Errors.from_active_record_object(person) }, status: 422
end

This will create one error for each field of the main object. The code will be “field_invalid” and the message will a comma-joined list of what’s wrong with that field, e.g. “Amount can’t be blank, Amount must be a number”.

Remember, for APIs, you don’t want to send bad user data directly to the API, so this mechanism isn’t designed for form fields and all the other things Rails gives you. It’s for the API client to be able to tell the programmer what went wrong.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(individual_errors) ⇒ Errors

Returns a new instance of Errors.



83
84
85
# File 'lib/stitches/errors.rb', line 83

def initialize(individual_errors)
  @individual_errors = individual_errors
end

Class Method Details

.from_active_record_object(object) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/stitches/errors.rb', line 70

def self.from_active_record_object(object)
  errors = object.errors.to_hash.map { |field,errors|
    code = "#{field}_invalid".parameterize
    message = if object.respond_to?(field) && object.send(field).respond_to?(:errors)
                object.send(field).errors.full_messages.sort.join(', ')
              else
                object.errors.full_messages_for(field).sort.join(', ')
              end
    Stitches::Error.new(code: code, message: message)
  }
  self.new(errors)
end

.from_exception(exception) ⇒ Object



60
61
62
63
64
65
66
67
68
# File 'lib/stitches/errors.rb', line 60

def self.from_exception(exception)
  code = exception.class.name.underscore.gsub(/_error$/,'')
  self.new([
    Error.new(
      code: code,
      message: exception.message
    )
  ])
end

Instance Method Details

#eachObject



91
92
93
94
95
96
97
98
99
# File 'lib/stitches/errors.rb', line 91

def each
  if block_given?
    @individual_errors.each do |error|
      yield error
    end
  else
    @individual_errors.each
  end
end

#sizeObject



87
88
89
# File 'lib/stitches/errors.rb', line 87

def size
  @individual_errors.size
end