Documentation for LLMs on building APIs with the Apia framework
Apia provides a structured error system with typed error responses, HTTP status codes, and automatic exception catching.
module MyAPI
module Errors
class ValidationError < Apia::Error
name "Validation error"
description "An error occurred with the input provided"
code :validation_error
http_status 422
field :details, [:string]
end
end
end
code(symbol)Sets the error code returned in the response. Must be a symbol.
code :validation_error
code :permission_denied
code :user_not_found
http_status(integer)Sets the HTTP status code for this error response.
http_status 404 # Not found
http_status 403 # Forbidden
http_status 422 # Unprocessable entity
http_status 401 # Unauthorized
description(string)A human-readable description of when this error occurs.
field(name, type, **options)Adds extra data fields to the error response. Follows the same syntax as object fields.
field :details, [:string]
field :details, :string, null: true do
description "Additional information regarding the reason"
end
field :given_token, :string
catch_exception(klass, &block)Maps a Ruby exception class to this error. When the exception is raised inside an endpoint action, it is automatically caught and converted to this API error.
catch_exception ActiveRecord::RecordInvalid do |fields, exception|
fields[:details] = exception.record.errors.full_messages
end
catch_exception ServiceErrors::ValidationError do |fields, exception|
fields[:details] = exception.errors
end
The block receives:
fields - A hash to populate with error field valuesexception - The caught exception instanceUse raise_error inside endpoint actions:
def call
user = User.find_by(uuid: request.arguments[:id])
if user.nil?
raise_error Errors::UserNotFoundError
end
unless user.active?
raise_error Errors::PermissionDeniedError, details: "User account is suspended"
end
end
raise_error Errors::ValidationError, details: ["Name is required"]
raise_error Errors::PermissionDeniedError
When errors are defined inline (in an authenticator, endpoint, or lookup), reference them by their string name:
raise_error "UserNotFound"
raise_error "InvalidAPIToken", details: "Token has expired"
You can also use the full error ID path:
raise_error "CoreAPI/MainAuthenticator/InvalidToken", given_token: token
Endpoints and authenticators must declare which errors they may raise using potential_error:
class CreateEndpoint < BaseEndpoint
# Reference an existing error class
potential_error Errors::ValidationError
potential_error Errors::PermissionDeniedError
# Define an inline error
potential_error "DuplicateEmail" do
code :duplicate_email
description "An account with this email already exists"
http_status 409
end
def call
raise_error Errors::ValidationError, details: ["Invalid input"]
# or
raise_error "DuplicateEmail"
end
end
When an error is raised, the response body has this structure:
{
"error": {
"code": "validation_error",
"description": "An error occurred with the input provided",
"detail": {
"details": ["Name is required", "Email is invalid"]
}
}
}
Apia provides these built-in error types that are raised automatically:
MissingArgumentErrorRaised when a required argument is not provided.
{
"error": {
"code": "missing_required_argument",
"description": "...",
"detail": { "path": ["properties", "name"] }
}
}
InvalidArgumentErrorRaised when an argument fails validation, parsing, or type checking.
{
"error": {
"code": "invalid_argument",
"description": "...",
"detail": { "path": ["age"], "issue": "validation_error" }
}
}
ScopeNotGrantedErrorRaised when the authenticated identity does not have the required scope. Returns HTTP 403.
class TokenOwnerSuspendedError < Apia::Error
code :token_owner_suspended
http_status 403
description "The owner of this token has been suspended"
end
class PermissionDeniedError < Apia::Error
code :permission_denied
http_status 403
description "The authenticated identity is not permitted to perform this action"
field :details, :string, null: true do
description "Additional information regarding the reason why permission was denied"
end
end
class ValidationError < Apia::Error
name "Validation error"
description "An error occurred with the input provided"
code :validation_error
http_status 422
field :details, [:string]
catch_exception ActiveRecord::RecordInvalid do |fields, exception|
fields[:details] = exception.record.errors.full_messages
end
catch_exception ServiceErrors::ValidationError do |fields, exception|
fields[:details] = exception.errors
end
end