23

Im just move to laravel 5 and im receiving errors from laravel in HTML page. Something like this:

Sorry, the page you are looking for could not be found.

1/1
NotFoundHttpException in Application.php line 756:
Persona no existe
in Application.php line 756
at Application->abort('404', 'Person doesnt exists', array()) in helpers.php line 

When i work with laravel 4 all works fine, the errors are in json format, that way i could parse the error message and show a message to the user. An example of json error:

{"error":{
"type":"Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException",
"message":"Person doesnt exist",
"file":"C:\\xampp\\htdocs\\backend1\\bootstrap\\compiled.php",
"line":768}}

How can i achieve that in laravel 5.

Sorry for my bad english, thanks a lot.

miken32
  • 42,008
  • 16
  • 111
  • 154
Andres
  • 383
  • 1
  • 4
  • 8
  • Specific to the abort function, it is possible to provide `abort` (and related `abort_if`, `abort_unless`) with a custom `Response` object (in the place where you'd put the status code) if you need more control than the options provided by the `abort` function. For example, if you need a JSON response (and cannot set the accept header to `application/json`), you could do `abort(new JsonResponse('A JSON string, could also be an array etc.', 403, ['Optional' => 'Headers'])` – user2428118 May 23 '22 at 14:00

8 Answers8

26

I came here earlier searching for how to throw json exceptions anywhere in Laravel and the answer set me on the correct path. For anyone that finds this searching for a similar solution, here's how I implemented app-wide:

Add this code to the render method of app/Exceptions/Handler.php

if ($request->ajax() || $request->wantsJson()) {
    return new JsonResponse($e->getMessage(), 422);
}

Add this to the method to handle objects:

if ($request->ajax() || $request->wantsJson()) {

    $message = $e->getMessage();
    if (is_object($message)) { $message = $message->toArray(); }

    return new JsonResponse($message, 422);
}

And then use this generic bit of code anywhere you want:

throw new \Exception("Custom error message", 422);

And it will convert all errors thrown after an ajax request to Json exceptions ready to be used any which way you want :-)

dstick
  • 286
  • 3
  • 4
  • 10
    if Laravel 5.1, the return should read "return response()->json($e->getMessage(), 422);" – Eric_WVGG Sep 04 '15 at 14:45
  • This works. When the handling code is not there, Laravel returns an HTTP 500 error, regardless of the specific error thrown in the code. E.g. `abort(403)` would return a 500 error for ajax requests. Did you experience the same? This must be a bug? – clapas Feb 13 '16 at 16:28
  • This saved my life. It's 2017 and I'm still using 5.1 so this is really useful for me. I passed 200 to the second argument when handling a FatalErrorException because I want the user to get an alert with a useful message rather than an obscure message like Internal Server Error. This lets the page render normally and gives the user useful feedback. – DavidHyogo Jan 08 '17 at 10:38
12

Laravel 5.1

To keep my HTTP status code on unexpected exceptions, like 404, 500 403...

This is what I use (app/Exceptions/Handler.php):

 public function render($request, Exception $e)
{
    $error = $this->convertExceptionToResponse($e);
    $response = [];
    if($error->getStatusCode() == 500) {
        $response['error'] = $e->getMessage();
        if(Config::get('app.debug')) {
            $response['trace'] = $e->getTraceAsString();
            $response['code'] = $e->getCode();
        }
    }
    return response()->json($response, $error->getStatusCode());
}
Ignacio Pascual
  • 1,895
  • 1
  • 21
  • 18
6

Laravel 5 offers an Exception Handler in app/Exceptions/Handler.php. The render method can be used to render specific exceptions differently, i.e.

public function render($request, Exception $e)
{
    if ($e instanceof API\APIError)
        return \Response::json(['code' => '...', 'msg' => '...']);
    return parent::render($request, $e);
}

Personally, I use App\Exceptions\API\APIError as a general exception to throw when I want to return an API error. Instead, you could just check if the request is AJAX (if ($request->ajax())) but I think explicitly setting an API exception seems cleaner because you can extend the APIError class and add whatever functions you need.

Zane
  • 4,652
  • 1
  • 29
  • 26
6

Edit: Laravel 5.6 handles it very well without any change need, just be sure you are sending Accept header as application/json.


If you want to keep status code (it will be useful for front-end side to understand error type) I suggest to use this in your app/Exceptions/Handler.php:

public function render($request, Exception $exception)
{
    if ($request->ajax() || $request->wantsJson()) {

        // this part is from render function in Illuminate\Foundation\Exceptions\Handler.php
        // works well for json
        $exception = $this->prepareException($exception);

        if ($exception instanceof \Illuminate\Http\Exception\HttpResponseException) {
            return $exception->getResponse();
        } elseif ($exception instanceof \Illuminate\Auth\AuthenticationException) {
            return $this->unauthenticated($request, $exception);
        } elseif ($exception instanceof \Illuminate\Validation\ValidationException) {
            return $this->convertValidationExceptionToResponse($exception, $request);
        }

        // we prepare custom response for other situation such as modelnotfound
        $response = [];
        $response['error'] = $exception->getMessage();

        if(config('app.debug')) {
            $response['trace'] = $exception->getTrace();
            $response['code'] = $exception->getCode();
        }

        // we look for assigned status code if there isn't we assign 500
        $statusCode = method_exists($exception, 'getStatusCode') 
                        ? $exception->getStatusCode()
                        : 500;

        return response()->json($response, $statusCode);
    }

    return parent::render($request, $exception);
}
Bilal Gultekin
  • 4,831
  • 3
  • 22
  • 27
  • This worked really well, returns a huge json with stack trace, but can easly see last error at the top – htafoya Nov 24 '17 at 03:05
3

On Laravel 5.5, you can use prepareJsonResponse method in app/Exceptions/Handler.php that will force response as JSON.

/**
 * 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)
{
    return $this->prepareJsonResponse($request, $exception);
}
0

Instead of

if ($request->ajax() || $request->wantsJson()) {...}

use

if ($request->expectsJson()) {...}

vendor\laravel\framework\src\Illuminate\Http\Concerns\InteractsWithContentTypes.php:42

public function expectsJson()
{
    return ($this->ajax() && ! $this->pjax()) || $this->wantsJson();
}
0

I updated my app/Exceptions/Handler.php to catch HTTP Exceptions that were not validation errors:

public function render($request, Exception $exception)
{
    // converts errors to JSON when required and when not a validation error
    if ($request->expectsJson() && method_exists($exception, 'getStatusCode')) {
        $message = $exception->getMessage();
        if (is_object($message)) {
            $message = $message->toArray();
        }

        return response()->json([
            'errors' => array_wrap($message)
        ], $exception->getStatusCode());
    }

    return parent::render($request, $exception);
}

By checking for the method getStatusCode(), you can tell if the exception can successfully be coerced to JSON.

james2doyle
  • 1,399
  • 19
  • 21
0

If you want to get Exception errors in json format then open the Handler class at App\Exceptions\Handler and customize it. Here's an example for Unauthorized requests and Not found responses

public function render($request, Exception $exception)
{
    if ($exception instanceof AuthorizationException) {
        return response()->json(['error' => $exception->getMessage()], 403);
    }

    if ($exception instanceof ModelNotFoundException) {
        return response()->json(['error' => $exception->getMessage()], 404);
    }

    return parent::render($request, $exception);
}
faye.babacar78
  • 774
  • 7
  • 12