Anyone know what is the best way to handle errors in Laravel, there is any rules or something to follow ?
Currently i'm doing this :
public function store(Request $request) { $plate = Plate::create($request->all()); if ($plate) { return $this->response($this->plateTransformer->transform($plate)); } else { // Error handling ? // Error 400 bad request $this->setStatusCode(400); return $this->responseWithError("Store failed."); } }
And the setStatusCode and responseWithError come from the father of my controller :
public function setStatusCode($statusCode) { $this->statusCode = $statusCode; return $this; } public function responseWithError ($message ) { return $this->response([ 'error' => [ 'message' => $message, 'status_code' => $this->getStatusCode() ] ]); }
But is this a good way to handle the API errors, i see some different way to handle errors on the web, what is the best ?
Thanks.
Note: This solution will not work for Authentication/Validation errors but most of the time these both errors are well managed by Laravel with proper human-readable response messages. You can use $response['message'] = Symfony\Component\HttpFoundation\Response::$statusTexts[$statusCode] instead of your long switch.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With