Andres
Andres

Reputation: 383

How to send Laravel error responses as JSON

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.

Upvotes: 23

Views: 33676

Answers (8)

faye.babacar78
faye.babacar78

Reputation: 852

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);
}

Upvotes: 0

Bilal Gultekin
Bilal Gultekin

Reputation: 5311

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);
}

Upvotes: 6

Muhammad Zamroni
Muhammad Zamroni

Reputation: 113

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);
}

Upvotes: 4

james2doyle
james2doyle

Reputation: 1429

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.

Upvotes: 0

Damian Domański
Damian Domański

Reputation: 1

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();
}

Upvotes: 0

Ignacio Pascual
Ignacio Pascual

Reputation: 1893

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());
}

Upvotes: 12

dstick
dstick

Reputation: 286

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 :-)

Upvotes: 26

Zane
Zane

Reputation: 4752

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.

Upvotes: 6

Related Questions