jenky/hades

Error response formatter for Laravel app

2.2.0 2024-04-15 02:11 UTC

This package is auto-updated.

Last update: 2025-03-04 16:10:38 UTC


README

Latest Version on Packagist Github Actions Codecov Total Downloads Software License

Dealing with errors when building an API can be a pain. Instead of manually building error responses you can simply throw an exception and the Hades will handle the response for you.

Installation

You may use Composer to install this package into your Laravel project:

$ composer require jenky/hades

Configuration

Generic Error Response Format

By default all thrown exceptions will be transformed to the following format:

{
    'message' => ':message', // The exception message
    'status' => ':status_code', // The corresponding HTTP status code, default to 500
    'errors' => ':errors', // The error bag, typically validation error messages
    'code' => ':code', // The exception code
    'debug' => ':debug', // The debug information
}

The debug information only available when application is not in production environment and debug mode is on.

Example:

curl --location --request GET 'http://myapp.test/api/user' \
--header 'Accept: application/json'
{
  "message": "Unauthenticated.",
  "type": "AuthenticationException",
  "status": 401,
  "code": 0,
}

Any keys that aren't replaced with corresponding values will be removed from the final response.

Formatting Exception

If you would like to use different error format for your application, you should call the Hades::errorFormat() method in the boot method of your App\Providers\AppServiceProvider class:

use Jenky\Hades\Hades;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Hades::errorFormat([
        'message' => ':message',
        'error_description' => ':error',
    ]);
}

Customizing Exception Response

Hades uses api-error internally. Please see the exception transformations to see how it works.

To add a custom transformers, you can use the config file

// configs/hades.php

return [

    'transformers' => [
        App\Exceptions\Transformers\MyCustomTransformer::class,
    ],

];

Alternatively, if Laravel can't inject your custom exception transformer, you may wish to register the exception transformer with the api_error.exception_transformer tag in your service provider. Typically, you should call this method from the register method of your application's App\Providers\AppServiceProvider class:

use App\Exceptions\Transformers\MyCustomTransformer;
use Illuminate\Contracts\Debug\ExceptionHandler;

public function register(): void
{
    $this->app->bind(MyCustomTransformer::class, static fn () => 'your binding logic');

    $this->app->tag('api_error.exception_transformer', MyCustomTransformer::class);
}

Content Negotiation

Forcing the JSON Response

By default, Laravel expects the request should contains header Accept with the MIME type application/json or custom MIME with json format such as application/vnd.myapp.v1+json in order to return JSON response. Otherwise your may get redirected to login page if the credentials are invalid or missing/passing invalid authorization token.

While this is a good design practice, sometimes you may wish to attach the header to request automatically, such as using Laravel as pure API backend. To do this, you should call the Hades::forceJsonOutput() method within the boot method of your App\Providers\AppServiceProvider.

use Jenky\Hades\Hades;

public function boot(): void
{
    Hades::forceJsonOutput();
}

Hades will add the header Accept: application/json to all incoming API requests. If you want to use custom MIME type, you may use the withMimeType to specify the MIME type:

Hades::forceJsonOutput()
    ->withMimeType('application/vnd.myapp.v1+json');

Identify API Requests

In order to force the response to return JSON output, Hades needs to identify the incoming request so it doesn't add the Accept header on your normal HTML pages.

By default, all your API routes defined in routes/api.php have /api URI prefix automatically applied. Hades will inspects the incoming request URI and determines it's URI matches the /api prefix.

To customize this behavior, you may pass the closure to Hades::forceJsonOutput() to instruct Hades how to identify the incoming request:

use Illuminate\Http\Request;

Hades::forceJsonOutput(static function (Request $request) {
    return $request->is('api/v1/*');
});

If your application is built solely for API use, you can configure the request to always return a JSON response.

use Illuminate\Http\Request;

Hades::forceJsonOutput(static fn () => true);

Change log

Please see CHANGELOG for more information on what has changed recently.

Testing

$ composer test

Contributing

Please see CONTRIBUTING and CODE_OF_CONDUCT for details.

Security

If you discover any security related issues, please email contact@lynh.me instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.