Laravel API, how to properly handle errors Laravel API, how to properly handle errors laravel laravel

Laravel API, how to properly handle errors


Try this, i have used it in my project (app/Exceptions/Handler.php)

public function render($request, Exception $exception){    if ($request->wantsJson()) {   //add Accept: application/json in request        return $this->handleApiException($request, $exception);    } else {        $retval = parent::render($request, $exception);    }    return $retval;}

Now Handle Api exception

private function handleApiException($request, Exception $exception){    $exception = $this->prepareException($exception);    if ($exception instanceof \Illuminate\Http\Exception\HttpResponseException) {        $exception = $exception->getResponse();    }    if ($exception instanceof \Illuminate\Auth\AuthenticationException) {        $exception = $this->unauthenticated($request, $exception);    }    if ($exception instanceof \Illuminate\Validation\ValidationException) {        $exception = $this->convertValidationExceptionToResponse($exception, $request);    }    return $this->customApiResponse($exception);}

After that custom Api handler response

private function customApiResponse($exception){    if (method_exists($exception, 'getStatusCode')) {        $statusCode = $exception->getStatusCode();    } else {        $statusCode = 500;    }    $response = [];    switch ($statusCode) {        case 401:            $response['message'] = 'Unauthorized';            break;        case 403:            $response['message'] = 'Forbidden';            break;        case 404:            $response['message'] = 'Not Found';            break;        case 405:            $response['message'] = 'Method Not Allowed';            break;        case 422:            $response['message'] = $exception->original['message'];            $response['errors'] = $exception->original['errors'];            break;        default:            $response['message'] = ($statusCode == 500) ? 'Whoops, looks like something went wrong' : $exception->getMessage();            break;    }    if (config('app.debug')) {        $response['trace'] = $exception->getTrace();        $response['code'] = $exception->getCode();    }    $response['status'] = $statusCode;    return response()->json($response, $statusCode);}

Always add Accept: application/json in your api or json request.


Laravel is already able to manage json responses by default.

Withouth customizing the render method in app\Handler.php you can simply throw a Symfony\Component\HttpKernel\Exception\HttpException, the default handler will recognize if the request header contains Accept: application/json and will print a json error message accordingly.

If debug mode is enabled it will output the stacktrace in json format too.

Here is a quick example:

<?php...use Symfony\Component\HttpKernel\Exception\HttpException;class ApiController{    public function myAction(Request $request)    {        try {            // My code...        } catch (\Exception $e) {            throw new HttpException(500, $e->getMessage());        }        return $myObject;    }}

Here is laravel response with debug off

{    "message": "My custom error"}

And here is the response with debug on

{    "message": "My custom error",    "exception": "Symfony\\Component\\HttpKernel\\Exception\\HttpException",    "file": "D:\\www\\myproject\\app\\Http\\Controllers\\ApiController.php",    "line": 24,    "trace": [        {            "file": "D:\\www\\myproject\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\ControllerDispatcher.php",            "line": 48,            "function": "myAction",            "class": "App\\Http\\Controllers\\ApiController",            "type": "->"        },        {            "file": "D:\\www\\myproject\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Route.php",            "line": 212,            "function": "dispatch",            "class": "Illuminate\\Routing\\ControllerDispatcher",            "type": "->"        },        ...    ]}

Using HttpException the call will return the http status code of your choice (in this case internal server error 500)


In my opinion I'd keep it simple.

Return a response with the HTTP error code and a custom message.

return response()->json(['error' => 'You need to add a card first'], 500);

Or if you want to throw a caught error you could do :

   try {     // some code    } catch (Exception $e) {        return response()->json(['error' => $e->getMessage()], 500);    }

You can even use this for sending successful responses:

return response()->json(['activeSubscription' => $this->getActiveSubscription()], 200);

This way no matter which service consumes your API it can expect to receive the same responses for the same requests.

You can also see how flexible you can make it by passing in the HTTP status code.