2025-12-07
#backend
#error-handling
#laravel

Enterprise Exception Handling

Centralized error handling using Marker Interfaces and global handlers.

The project uses a centralized approach to error handling based on Marker Interfaces. This keeps the domain layer clean of HTTP dependencies.

Principles

  1. Clean Domain: Domain exceptions (ReservationExpiredException) know nothing about HTTP statuses (404, 422). They simply state a business logic error fact.
  2. Happy Path Controllers: Controllers do not use try-catch. They expect successful execution.
  3. Global Handler: A single component in the Core layer converts exception types into HTTP responses.

Implementation

1. Marker Interfaces (Core Layer)

Interfaces corresponding to error types are defined in app/Core/Exceptions:

php
interface UnauthorizedExceptionInterface {}   // -> 401
interface ConflictExceptionInterface {}       // -> 409
interface UnprocessableExceptionInterface {}  // -> 422

2. Domain Exceptions (Domain Layer)

Exceptions implement the corresponding interfaces:

php
class DoubleBookingException extends Exception implements ConflictExceptionInterface
{
    protected $message = "This slot is already booked.";
}

3. Handling (Core Layer)

CustomExceptionHandler intercepts exceptions and uses a response factory:

php
// In the register(Exceptions $exceptions) method
$exceptions->render(function (Throwable $e) {
    if ($e instanceof ConflictExceptionInterface) {
        // Forms a standardized JSON response
        return $this->responseFactory->conflict($e->getMessage());
    }
    return null;
});

Advantages

  • DRY: No need to write try-catch in every controller.
  • Consistency: API error format (JSON structure) is guaranteed to be uniform across the application.
  • Clarity: The exception class immediately indicates the category of error it belongs to.

Connected Thoughts

Egor Zdioruc | Lead Full Stack Developer | Laravel & AI Solutions