Iam using Redis as cache in Laravel.
But I cannot catch Exception when laravel cannot connect to Redis (redis stopped, ...). I want catch this exception to reponse to client by JSON.
How can I do it ?
You can use render() function of App\Exceptions\Handler class as:
public function render($request, Exception $exception)
{
if ($exception instanceof SomeRedisException) {
return response()->json('Redis Error',500);
}
return parent::render($request, $exception);
}
Docs
In case of Redis connection error - the RedisException will be thrown by phpredis extension.
Somewhere in your Controller or Middleware:
try {
// Call Laravel Cache facade when Redis connection is failing
// This will throw exception
Cache::get('cache_key');
} catch (RedisException $exception) {
// In case Redis error - do custom response
Log::error('Redis error', [
'message' => $exception->getMessage(),
'trace' => $exception->getTrace()
]);
return response()->json([
'error' => 'your error message to client'
]);
}
Related
I am developing a rest API and sometimes the frontend call an endpoint with the wrong HTTP request type. For example, I have a route (/users/unassigned) and the type of the route is "GET". Imagin my frontend call this route with a "POST" request. the following error occurs.
The POST method is not supported for this route. Supported methods: GET, HEAD, PUT, DELETE.
What I want is that the API response a JSON in these situations and I can handle the exception.I have used the Route::fallback but this method catch every exception of the routes. I need a function that only handles the told problem.
you can make some adjustment in your exception handler.
in app/Exceptions/Handler.php file's render function
public function render($request, Exception $exception)
{
if ($exception instanceof MethodNotAllowedHttpException) {
if ($request->ajax()) {
return response()->json(['error' => 'Route Not Found'], 404);
}
else {
//something else
}
}
return parent::render($request, $exception);
}
and add use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; at the top use section.
One way is to handle it with app/Exceptions/Handler.php:
public function render($request, Exception $e)
{
if ($request->ajax() || $request->wantsJson()) {
return response()->json([
'error' => $e->getMessage(),
], 400);
}
return parent::render($request, $e);
}
This will ouput the error message as json for all exceptions when the request is made by ajax or the request expect json.
You can also add a check for type of exception like this:
if ($exception instanceof MethodNotAllowedHttpException) {
// Code...
}
Thank you so much.
I use the following code in my handler.php.
{
if ($this->isHttpException($exception)) {
switch ($exception->getStatusCode()) {
// not authorized
case '403':
return Response()->json(["error" => "not authorized."],403);
break;
// not found
case '404':
return Response()->json(["error" => "Route not found."],404);
break;
// internal error
case '500':
return Response()->json(["error" => "internal error."],500);
break;
case '405':
return Response()->json(["error" => "request type not match."],405);
break;
default:
return $this->renderHttpException($exception);
break;
}
}
else {
return parent::render($request, $exception);
}
}
The main point is http code 405 for not allowed methodes. special thanks to #apokryfos.
Check what type of request you are getting in your $request variable, then handle it with condition.
change in your Handler.php
like
protected $dontReport = [
\Illuminate\Auth\AuthenticationException::class,
\Illuminate\Auth\Access\AuthorizationException::class,
\Symfony\Component\HttpKernel\Exception\HttpException::class,
\Illuminate\Database\Eloquent\ModelNotFoundException::class,
\Illuminate\Session\TokenMismatchException::class,
\Illuminate\Validation\ValidationException::class,
//
];
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
$arr = array("status" => 400, "message" =>"Unauthorized access", "data" => array());
return \Response::json($arr);
}
return redirect()->guest('login');
}
Using laravel5.8. Using both web and API(Token Gaurd).
when using api call with invalid api_token parameter receiving an error Route:Login not defined. I want the response in JSON. Read in Forum I need to use the below way in app\Exceptions\Handler.php and it works. I have web gaurd for some of the paths. I want the route:login to work when its a web gaurd and return json response when using api gaurd. How can I do it in Laravel 5.8?
public function render($request, Exception $exception)
{
// dd(get_class($exception));
// return parent::render($request, $exception);
return response()->json(
[
'errors' => [
'status' => 401,
'message' => 'Unauthenticated',
]
], 401
);
}
I put the logic in unauthenticated function, combines with expectsJson() should solve your problem
// in app\Exceptions\Handler.php
public function render($request, Exception $exception)
{
return parent::render($request, $exception);
}
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['status' => 401,'message' => 'Unauthenticated.'], 401);
}
return redirect()->guest('/');
}
I'm using ThrottleRequest to throttle login attempts.
In Kendler.php i have
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
and my route in web.php
Route::post('login', ['middleware' => 'throttle:3,1', 'uses' => 'Auth\LoginController#authenticate']);
When i login fourth time, it return status 429 with message 'TOO MANY REQUESTS.'
(by default i guess)
But i just want to return error message, somethings like:
return redirect('/login')
->withErrors(['errors' => 'xxxxxxx']);
Anybody help me! THANK YOU!
You can either extend the middleware and override the buildException() method to change the message it passes when it throws a ThrottleRequestsException or you can use your exception handler to catch the ThrottleRequestsException and do whatever you want.
so in Exceptions/Handler.php you could do something like
use Illuminate\Http\Exceptions\ThrottleRequestsException;
public function render($request, Exception $exception)
{
if ($exception instanceof ThrottleRequestsException) {
//Do whatever you want here.
}
return parent::render($request, $exception);
}
I'm working on a rest api project.
I was struggling with an issue. As I get the token expiration error, the generated code will be something like this :
public function authenticate(Request $request){
$this->checkForToken($request);
try {
if (! $this->auth->parseToken()->authenticate()) {
throw new UnauthorizedHttpException('jwt-auth', 'User not found');
}
} catch (JWTException $e) {
throw new UnauthorizedHttpException('jwt-auth', $e->getMessage(), $e, $e->getCode());
}
}
This code is written in this file :
vendor/tymon/jwt-auth/src/Http/Middleware/BaseMiddleware.php
How can I return this as a JSON type?
Catch that exception in your App\Exceptions\Handler class' render method and return a response formatted as json:
// Handler.php
// import the class of the exception you want to render a json response for at the top
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
...
public function render($request, Exception $exception)
{
// if your api client has the correct content-type this expectsJson()
// should work. if not you may use $request->is('/api/*') to match the url.
if($request->expectsJson())
{
if($exception instanceof UnauthorizedHttpException) {
return response()->json('Unauthorized', 403);
}
}
return parent::render($request, $e);
}
I was wondering if there is a way to catch all the exceptions that are thrown in a laravel app and store them in database ?
I have been looking at some packages but coudn't find anything that tells where and how to catch the exceptions.
for catch all errors and log them you need to edit App\Exceptions\Handler file like this
public function render($request, Exception $exception)
{
if ($exception){
// log the error
return response()->json([
'status' => $exception->getStatusCode(),
'error' => $exception->getMessage()
]);
}
return parent::render($request, $exception);
}
As stated in the Docs,
You need to have to customize the render() method of App\Exceptions\Handler.
Edit the app/Exceptions/Handler.php:
public function render($request, Exception $e)
{
$error =$e->getMessage();
//do your stuff with the error message
return parent::render($request, $exception);
}