Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

andersb's avatar

Returning JOSN:API errors instead of standard Error Handling results

If API request contain the header "Accept: application/json", then the standard Laravel 5.5 error handling returns a JSON object containing a "message"-field (in case of a development environment, the fields exception, file, line and trace are also present).

I am trying to alter this response to follow the JSON:API error format: http://jsonapi.org/examples/#error-objects

{
  "errors": [
    {
      "id": "unique-trace-code-abcdefg123456798",
      "code": "abcdefg123456798",
      "title": "Pass this message on to the app user, if needed.",
    }
  ]
}

Preferably, then the id would be the unique code assigned to the error by a report service like Bugsnag or Sentry.

The code should be the Exception name and the title should be the regular message.

I am wondering if this should be implemented as a condition ($request->expectsJson()) in the render() function in /app/Exceptions/Handler.php that checks if the requested format is JSON and returns a custom error Resource.

Does anyone have any experience with implementing such an error handling?

Thank you.

0 likes
2 replies
andersb's avatar
andersb
OP
Best Answer
Level 3

We ended up with a solution where we first rendered the request by the parent and then added the fields afterwards. That seemed to work for all errors.

We made the following changes to app\Exceptions\Handler.php

/**
 * Render an exception into an HTTP response.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Exception  $exception
 * @return \Illuminate\Http\Response
 */
public function render($request, Exception $exception)
{
    // Convert all non-http exceptions to a proper 500 http exception
    // if we don't do this exceptions are shown as a default template
    // instead of our own view in resources/views/errors/500.blade.php
    if ($this->shouldReport($exception) && !$this->isHttpException($exception) && !config('app.debug')) {
        $exception = new HttpException(500, 'Whoops!');
    }

    $response = parent::render($request, $exception);

    // If the API request wants JSON then return custom JSON API error
    if ($this->isApiCall($request) && $request->wantsJson()) {
        // add fields to the content
        $content = json_decode($response->getContent());
        $content->links = [
            'about' => App::make('url')->to('/errors/'.class_basename($exception)),
        ];
        $content->id = app('sentry')->getLastEventID();
        $content->code = class_basename($exception);
        // If debug, then add debug info
        if(config('app.env') !== 'production' && config('app.debug')) {
            $content->debug = [
                'message' => $exception->getMessage(),
                'exception' => get_class($exception),
                'file' => $exception->getFile(),
                'line' => $exception->getLine(),
                'trace' => collect($exception->getTrace())->map(function ($trace) {
                    return Arr::except($trace, ['args']);
                })->all(),
            ];
        }
        $response->setContent(json_encode($content));
    }

    return $response;
}

Please or to participate in this conversation.