skip to Main Content

Does anyone know how to make the application return in a general way anyexception using a response in Json format with the respective HTTP error and a descriptive message of the error occurred, without performing any type of redirection to the
time of occurrence?

This is an example of what I want

{
"errors": [],
"exception":
"Illuminate\Database\Eloquent\ModelNotFoundException",
"file":
"/var/www/project/vendor/laravel/framework/src/Illuminate/Database/Eloqu
ent/Builder.php",
"line": 598,
"message": "No query results for model
[App\Models\API\ModelName].",
"statusCode": 404
}

I was trying to do this from App/Exception/Handler.php

<?php

namespace AppExceptions;

use IlluminateFoundationExceptionsHandler as ExceptionHandler;
use Throwable;

class Handler extends ExceptionHandler
{
    /**
     * The list of the inputs that are never flashed to the session on validation exceptions.
     *
     * @var array<int, string>
     */
    protected $dontFlash = [
        'current_password',
        'password',
        'password_confirmation',
    ];

    /**
     * Register the exception handling callbacks for the application.
     */
    public function register(): void
    {
        $this->reportable(function (Throwable $e) {
            $Status = array('msg'=>$e);
            return response ($Status,$e);
        });
    }
}

2

Answers


  1. Create on Trait GlobalExceptionHandler in app/Traits directory

    <?php
    
    namespace AppTraits;
    
    use IlluminateDatabaseEloquentModelNotFoundException;
    use IlluminateDatabaseQueryException;
    use IlluminateValidationValidationException;
    use InvalidArgumentException;
    use SymfonyComponentHttpFoundationResponse;
    use SymfonyComponentHttpKernelExceptionNotFoundHttpException;
    use Throwable;
    
    trait GlobalExceptionHandler
    {
        /**
         * Get error data by exception
         *
         * @param Throwable $exception
         *
         * @return array
         */
        public function getErrorData(Throwable $exception): array
        {
            $response = $this->getExceptionData($exception);
    
            if (!isset($response['error_from'])) {
                $response['error_from'] = 'application name';
            }
    
            if (config('app.env') == 'local' || config('app.env') == 'staging') {
                $response = array_merge(
                    $response, [
                        '_message' => $exception->getMessage(),
                        '_exception' => class_basename($exception),
                        '_line' => $exception->getLine(),
                        '_file' => $exception->getFile(),
                    ]
                );
            }
    
            return $response;
        }
    
        /**
         * * Get error data by exception
         *
         * @param Throwable $exception
         *
         * @return array
         */
        private function getExceptionData(Throwable $exception): array
        {
            $exceptionActions = [
                'QueryException' => function (QueryException $exception) {
                    $code = $exception->getCode();
                    $databaseMessageByCode = [
                        23000 => __('record_already_exists'),
                    ];
                    return [
                        'code' => Response::HTTP_BAD_REQUEST,
                        'message' => $databaseMessageByCode[$code] ?? 'Database error!',
                    ];
                },
                'ModelNotFoundException' => function (ModelNotFoundException $exception) {
                    $modelName = last(explode('\', $exception->getModel()));
                    $ids = ' ' . implode(', ', $exception->getIds());
                    return [
                        'code' => Response::HTTP_NOT_FOUND,
                        'message' => "{$modelName}{$ids} " . __('does_not_exists'),
                    ];
                },
                'ValidationException' => function (ValidationException $exception) {
                    return [
                        'code' => Response::HTTP_UNPROCESSABLE_ENTITY,
                        'message' =>
                            collect($exception->errors())
                                ->flatten()
                                ->first() ?? $exception->getMessage(),
                        'errorMessages' => $exception->errors(),
                    ];
                },
                'NotFoundHttpException' => function (NotFoundHttpException $exception) {
                    return [
                        'code' => $exception->getStatusCode(),
                        'message' => __('http_request_does_not_exist'),
                    ];
                },
                'Exception' => function (Throwable $exception) {
                    $exceptionCode = Response::HTTP_INTERNAL_SERVER_ERROR;
                    $exceptionMessage = __('Internal Server Error');
                    if ($exception->getCode() > 200) {
                        $exceptionCode = $exception->getCode();
                        $exceptionMessage = $exception->getMessage();
                    }
                    return [
                        'code' => $exceptionCode,
                        'message' => $exceptionMessage,
                    ];
                },
            ];
            $className = isset($exceptionActions[class_basename($exception)])
                ? class_basename($exception)
                : 'Exception';
    
            return $exceptionActions[$className]($exception);
        }
    }
    

    And in App/Exception/Handler.php use Trait to render the exception

    <?php
    
    namespace AppExceptions;
    
    use AppTraitsGlobalExceptionHandler;
    use IlluminateFoundationExceptionsHandler as ExceptionHandler;
    use Throwable;
    
    class Handler extends ExceptionHandler
    {
        use GlobalExceptionHandler;
    
        /**
         * A list of the exception types that are not reported.
         *
         * @var array<int, class-string<Throwable>>
         */
        protected $dontReport = [
            //
        ];
    
        /**
         * A list of the inputs that are never flashed for validation exceptions.
         *
         * @var array<int, string>
         */
        protected $dontFlash = [
            'current_password',
            'password',
            'password_confirmation',
        ];
    
        /**
         * Register the exception handling callbacks for the application.
         *
         * @return void
         */
        public function register()
        {
            $this->renderable(function (Throwable $e) {
                $errorData = $this->getErrorData($e);
                return response()->json($errorData, $errorData['code']);
            });
    
            $this->reportable(function (Throwable $e) {
            
            });
        }
    }
    
    Login or Signup to reply.
  2. If you require as per the example

    There is some modification can be done to achieve it

    use Exception;
    use IlluminateFoundationExceptionsHandler as ExceptionHandler;
    use IlluminateHttpJsonResponse;
    use IlluminateHttpResponse;
    use Throwable;
    class Handler extends ExceptionHandler
    {
    public function render($request, Throwable $exception) { //..}
    
    protected function getStatusCode(Throwable $exception): int { //..}
    }
    

    in Handler class add below method

    public function render($request, Throwable $exception)
        {
                $statusCode = $this->getStatusCode($exception);
                $responseData = [
                    'errors' => [],
                    'exception' => get_class($exception),
                    'file' => $exception->getFile(),
                    'line' => $exception->getLine(),
                    'message' => $exception->getMessage(),
                    'statusCode' => $statusCode,
                ];
                return new JsonResponse($responseData, $statusCode);
    
        }
    
    

    In above render method return parent::render($request, $exception); is default

    protected function getStatusCode(Throwable $exception): int
        {
            if ($exception instanceof IlluminateDatabaseEloquentModelNotFoundException) {
                return Response::HTTP_NOT_FOUND;
            }
    
           if ($exception instanceof IlluminateAuthAuthenticationException) {
                return Response::HTTP_UNAUTHORIZED;
            }
    
            //..
    
            return Response::HTTP_INTERNAL_SERVER_ERROR;
        }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search