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