Errors

All errors that can be generated by the API must be defined as error objects. This tells the API how it should represent them to the consumer as well as providing information required for documentation.

Defining errors

Errors can be defined as classes (when they need to be shared across multiple endpoints) or inline. When defining them within a class they should inherit from the Apia::Error class.

Example definition

class ExampleError < Apia::Error

  # Defines information about the error for documentation
  name 'Example error'
  description 'Raised when an example is encountered but should not have been'

  # Defines the code that will be returned to the consumer
  code :example_error

  # Defines the HTTP status that should be returned when this error is encountered
  http_status 418

  # Define fields that should be included with this field
  field :details, :string

end

Raising errors

Errors can be raised by calling raise_error and providing either the name of the class (ExampleError) or the name of the error if it has been defined inline.

This example shows how to raise a class-defined error. You should also provide any fields that are required for the error as shown below with errors.

class ExampleEndpoint < Apia::Endpoint

  potential_error Errors::ValidationError

  def call
    # ...
    unless user.save
      raise_error Errors::ValidationError, errors: user.errors.full_messages
    end
  end

end

This example shows how to raise an inline error.

class ExampleEndpoint < Apia::Endpoint

  potential_error 'NotPermitted' do
    code :not_permitted
    http_status 406
  end

  def call
    raise_error 'NotPermitted'
  end

end

Catching exceptions

If any exception occurs during your application lifecycle, it will be returned to the user as an unhandled_exception error. You can, however, choose to catch certain exceptions and return them as proper errors. Here's an example of catching Active Record validation errors:

class ValidationError < Apia::Error

  # We can define things as normal for the error...
  code :validation_error
  http_status 416
  field :errors, [:string]

  # However, we're also going to specify that this error can catch the
  # desired type of exception. Here we say that if an ActiveRecord::RecordInvalid
  # exception is encountered, we'll catch that and return a `ValidationError`
  # propertly. The block allows you to popular fields for the exception from
  # the exception that was raised.
  catch_exception ActiveRecord::RecordInvalid do |fields, exception|
    fields[:errors] = exception.record.errors.full_messages
  end
end

This will only be caught if the ValidationError error has been specified as a potential error for the endpoint where the exception is raised. So, you need to make sure to specify these if you want exceptions to be caught automatically. An endpoint might look this like:

class ExampleEndpoint < Apia::Endpoint

  argument :user_id, :integer, required: true
  argument :properties, ArgumentSets::UserProperties, required: true

  field :user, Objects::User

  potential_error ValidationError

  def call
    user = User.find(request.arguments[:user_id])
    user.update!(request.arguments[:properties]) # Might raise the error here but will be caught
    response.add_field :user, user
  end

end
Edit this page on GitHub Updated at Mon, Mar 18, 2024