Search code examples
laravelapierror-handling

Laravel API, how to properly handle errors


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.


Solution

  • 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.