frootbox/exceptions

Frootbox Exceptions

Maintainers

Package info

github.com/Frootbox/Exceptions

pkg:composer/frootbox/exceptions

Statistics

Installs: 2 941

Dependents: 5

Suggesters: 0

Stars: 0

Open Issues: 0

0.1 2026-05-16 15:05 UTC

This package is auto-updated.

Last update: 2026-05-16 15:05:35 UTC


README

Small semantic exception package for Frootbox applications and libraries.

The package provides shared exception classes for common application states such as missing input, invalid input, missing resources, access denial, and runtime errors. These exceptions are intentionally transport-neutral: application code can throw them without knowing whether the error is later rendered as HTML, JSON, CLI output, or something else.

Installation

composer require frootbox/exceptions

Basic Usage

use Frootbox\Exceptions\InputMissing;
use Frootbox\Exceptions\NotFound;

if (empty($payload['email'])) {
    throw new InputMissing('Email is required.');
}

if ($customer === null) {
    throw new NotFound('Customer not found.');
}

Every exception extends Frootbox\Exceptions\BaseException, which extends PHP's native Exception.

Exception Classes

Exception Intended meaning HTTP status
AccessDenied Authenticated actor is not allowed to perform the action 403
ClassMissing Required PHP class is missing 500
ConfigurationMissing Required configuration value is missing 400
InputInvalid Provided input is present but invalid 400
InputMissing Required input value is missing 400
NotFound Requested resource or database row does not exist 404
NotLoggedIn Authentication is required 401
ParameterMissing Required parameter is missing 400
PermissionDenied Actor has insufficient permission 403
ResourceInvalid Resource exists but cannot be used as requested 400
ResourceMissing Required resource is missing 404
RuntimeError Internal application/runtime failure 500

HTTP Boundary Contract

Exceptions also implement:

Frootbox\Exceptions\Interfaces\HttpException

This interface exposes metadata for framework or adapter packages that need to render an error at an HTTP boundary:

public function getHttpStatusCode(): int;
public function getErrorCode(): string;
public function hasPublicMessage(): bool;

Example mapper:

use Frootbox\Exceptions\Interfaces\HttpException;

try {
    $response = $controller->execute();
}
catch (HttpException $exception) {
    http_response_code($exception->getHttpStatusCode());
    header('Content-Type: application/json; charset=utf-8');

    echo json_encode([
        'error' => [
            'code' => $exception->getErrorCode(),
            'message' => $exception->hasPublicMessage()
                ? $exception->getMessage()
                : 'Unexpected API error.',
        ],
    ]);

    exit;
}

Transport packages such as REST servers should depend on this interface instead of matching every concrete exception class individually.

Error Codes

Each exception exposes a stable machine-readable code through getErrorCode().

(new NotFound('Customer not found.'))->getErrorCode(); // not_found

If a concrete exception does not define a custom code, BaseException derives one from the class name.

Public Messages

Most domain and validation exceptions expose their message publicly. Internal failures such as RuntimeError and ClassMissing mark their message as non-public:

$exception->hasPublicMessage(); // false

HTTP renderers should respect this and replace the message with a generic one.

Properties

All exceptions accept optional properties for structured context:

throw new InputMissing(properties: [ 'email' ]);

The properties can be read with:

$exception->getProperties();

InputMissing keeps the existing legacy behavior: when no message is provided but properties are present, its message becomes Field.

Translated Messages

toString() builds a translation key compatible with Frootbox translators:

$exception->toString($translator);

If no translation is found, it falls back to the explicit exception message.