DEV Community

Cover image for Laravel Centralized Exception Handling
Anas Hussain
Anas Hussain

Posted on

Laravel Centralized Exception Handling

Introduction

Error handling is critical for building robust and user-friendly applications. In this post, we’ll explore three approaches to exception handling in Laravel and focus on configuring centralized exception handling in the bootstrap/app.php file using withExceptions.


Why Centralized Error Handling?

  • Keeps the code DRY by avoiding repetitive try-catch blocks.
  • Enhances maintainability by consolidating error handling logic in one place.
  • Improves user experience with consistent error responses.

Exploring Approaches to Exception Handling

1. Exception Handling per Method

  • Handle exceptions locally within each method.
  • Drawback: Repetitive code and harder to maintain.

Example:

public function store(Request $request) {
    try {
        // Code logic here
    } catch (QueryException $e) {
        return back()->with('error', 'Database error occurred.');
    }
}
Enter fullscreen mode Exit fullscreen mode

2. Exception Handling in bootstrap/app.php

  • Centralized error handling at the application level.
  • Flexible, DRY, and maintainable.
  • Focus of this tutorial.

3. Custom Middleware for Exception Handling

  • Ideal for handling specific exceptions for routes or groups.
  • Adds complexity when handling application-wide errors.

Configuring Exception Handling in bootstrap/app.php

Step 1: Update the bootstrap/app.php File

Use Laravel's Application class to set up centralized exception handling with withExceptions.

Here’s the complete code snippet:

<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use App\Http\Middleware\EnsureAdminIsAuthenticated;
use Illuminate\Http\Request;
use Illuminate\Database\QueryException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__ . '/../routes/web.php',
        api: __DIR__ . '/../routes/api.php',
        commands: __DIR__ . '/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->alias([
            "admin_auth" => EnsureAdminIsAuthenticated::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions) {

        // Handling database query exceptions
        $exceptions->render(function (QueryException $e, Request $request) {
            Log::error('Database error: ' . $e->getMessage(), [
                'error' => $e->getMessage(),
                'url' => $request->fullUrl(),
                'user_id' => auth()->check() ? auth()->id() : 'guest',
            ]);

            return redirect()->back()->with('warning', 'A database error occurred. Please try again.');
        });

        // Handling not found exceptions
        $exceptions->render(function (NotFoundHttpException $e, Request $request) {
            if ($e->getPrevious() instanceof ModelNotFoundException) {
                Log::error('Model not found: ' . $e->getMessage(), [
                    'error' => $e->getMessage(),
                    'url' => $request->fullUrl(),
                    'user_id' => auth()->check() ? auth()->id() : 'guest',
                ]);

                return redirect()->back()->with('warning', 'Requested resource not found.');
            }
        });

        // Handling validation exceptions
        $exceptions->render(function (ValidationException $e, Request $request) {
            Log::error('Validation error: ' . $e->getMessage(), [
                'user_id' => auth()->id(),
                'url' => $request->fullUrl(),
                'input' => $request->all(),
            ]);

            return redirect()->back()->withErrors($e->validator)->withInput();
        });

        // Handling generic exceptions
        $exceptions->render(function (Exception $e, Request $request) {
            Log::error('An unexpected error occurred.', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'url' => $request->fullUrl(),
                'user_id' => auth()->check() ? auth()->id() : 'guest',
            ]);

            return redirect()->back()->with('warning', 'An unexpected error occurred. Please try again.');
        });

    })->create();
Enter fullscreen mode Exit fullscreen mode

Step 2: Explanation of Each Exception

QueryException

  • Catches database-related errors.
  • Logs the error details and redirects users back with a warning.

ModelNotFoundException

  • Handles cases when a model cannot be found.
  • Logs the error and displays a user-friendly message.

ValidationException

  • Captures validation errors and sends them back to the form.
  • Logs the input data and errors for debugging.

Generic Exception

  • Catches all other unhandled exceptions.
  • Logs the error message and stack trace for further investigation.

Step 3: Testing the Configuration

  1. Trigger each type of exception (e.g., invalid form data, nonexistent routes).
  2. Verify the logs contain detailed error information.
  3. Ensure the user sees friendly and consistent error messages.

Advantages of This Approach

  • Centralized Control: All exception logic in one place.
  • Improved User Experience: Users are redirected with helpful messages.
  • Debugging Made Easy: Logs provide detailed context for errors.

Conclusion

Centralized exception handling in bootstrap/app.php is an efficient way to manage errors in a Laravel application. By following this guide, you can handle exceptions systematically, maintain clean controllers, and enhance user experience.

Top comments (0)