Change message of invalid scope - php

How can I change invalid scope(s) provided message in Laravel Passport

try to update this render function in app/Exceptions/Handler.php file
public function render($request, Exception $exception)
{
if ($exception instanceof \Laravel\Passport\Exceptions\MissingScopeException)
{
return response()->json(['message' => 'your message here']);
//abort(401);
}
return parent::render($request, $e);
}

You can catch that as an Exception like so in your controller:
try {
// Whatever you are doing which leads to such error.
} catch (MissingScopeException $e) {
return response()->json(['message' => 'YOUR DESIRED MESSAGE.']);
}
By the way, this is where leads to such exception.

I'm using laravel/framework v8.10.0 and laravel/passport v10.0.1.
If you are using Passport only for API you could change directly the throw exception in the Middleware.
Steps:
Go to app/Http/Kernel.php.
In the $routeMiddleware array you need to have the line:
'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class.
Go to the CheckForAnyScope middleware with Ctrl + click (Windows) or Cmd + click (MacOS).
In the CheckForAnyScope middleware go to handle function and before the line:
throw new MissingScopeException($scopes); add your custom error response.
Example with code:
public function handle($request, $next, ...$scopes)
{
if (! $request->user() || ! $request->user()->token()) {
throw new AuthenticationException;
}
foreach ($scopes as $scope) {
if ($request->user()->tokenCan($scope)) {
return $next($request);
}
}
// Custom error response
return response()->json(['success' => false, 'errors' => ['This type of user cannot do this action.'], 'data' => null]);
// This line can be commented or deleted.
throw new MissingScopeException($scopes);
}

Related

render function in Handler.php not working Laravel 8

I want to return a JSON response instead of the default 404 error page when ModelNotFoundException occurs. To do this, I wrote the following code into app\Exceptions\Handler.php :
public function render($request, Exception $exception)
{
if ($exception instanceof ModelNotFoundException) {
return response()->json([
'error' => 'Resource not found'
], 404);
}
return parent::render($request, $exception);
}
However it doesn't work. When the ModelNotFoundException occurs, Laravel just shows a blank page. I find out that even declaring an empty render function in Handler.php makes Laravel display a blank page on ModelNotFoundException.
How can I fix this so it can return JSON/execute the logic inside the overriden render function?
In Laravel 8x, You need to Rendering Exceptions in register() method
use App\Exceptions\CustomException;
/**
* Register the exception handling callbacks for the application.
*
* #return void
*/
public function register()
{
$this->renderable(function (CustomException $e, $request) {
return response()->view('errors.custom', [], 500);
});
}
For ModelNotFoundException you can do it as below.
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
public function register()
{
$this->renderable(function (NotFoundHttpException $e, $request) {
return response()->json(...);
});
}
By default, the Laravel exception handler will convert exceptions into an HTTP response for you. However, you are free to register a custom rendering Closure for exceptions of a given type. You may accomplish this via the renderable method of your exception handler. Laravel will deduce what type of exception the Closure renders by examining the type-hint of the Closure:
More info about the error exception
This code doesn't work for me (in Laravel 8.74.0):
$this->renderable(function (ModelNotFoundException$e, $request) {
return response()->json(...);
});
Don't know why, but ModelNotFoundException is directly forwarded to NotFoundHttpException (which is a part of Symfony Component) that used by Laravel and will ultimately triggers a 404 HTTP response. My workaround is checking the getPrevious() method of the exception:
$this->renderable(function (NotFoundHttpException $e, $request) {
if ($request->is('api/*')) {
if ($e->getPrevious() instanceof ModelNotFoundException) {
return response()->json([
'status' => 204,
'message' => 'Data not found'
], 200);
}
return response()->json([
'status' => 404,
'message' => 'Target not found'
], 404);
}
});
And then we will know that this exception come from ModelNotFoundException and return a different response with NotFoundHttpException.
Edit
This is why ModelNotFoundException thrown as NotFoundHttpException
This one is my Handler file:
use Throwable;
public function render($request, Throwable $exception)
{
if( $request->is('api/*')){
if ($exception instanceof ModelNotFoundException) {
$model = strtolower(class_basename($exception->getModel()));
return response()->json([
'error' => 'Model not found'
], 404);
}
if ($exception instanceof NotFoundHttpException) {
return response()->json([
'error' => 'Resource not found'
], 404);
}
}
}
This one is only for all request in API route. If you want to catch all request, so remove the first if.
Please note that by default Laravel emits a JSON representation of an exception ONLY when you send a request with the header parameter Accept: application/json! For all other requests, Laravel sends normal HTML rendered output.

Laravel 5.7 ModelNotFoundException not return json for API calls

I want to return a json response when an api call is made to a laravel 5.7 app api route when the model is not found. To do this I have modified the render() method of app\Exceptions\Handler.php like this
public function render($request, Exception $exception)
{
if ($exception instanceof ModelNotFoundException && $request->wantsJson()) {
return response()->json(['message' => 'Not Found!'], 404);
}
return parent::render($request, $exception);
}
and my controller show() method is using a Book model like this
public function show(Book $book)
{
return new BookResource($book->load('ratings'));
}
Test on postman, a get call to localhost:8000/api/books/1 (id 1 has been deleted) keeps returning the default laravel 404 not found page instead of json.
Have I missed a step or something? I also noticed that adding a conditional statement inside the controller show() method like this
public function show(Book $book)
{
if ($book) {
return new BookResource($book->load('ratings'));
} else {
return response()->json(['message' => 'Not found'], 404);
}
}
returns the same html result instead of json.
What will be the proper way to handle this scenario?
Your code is correct. The problem is that you are probably testing it on a Local environment so in your .env you have set:
APP_DEBUG=true, switch it to APP_DEBUG=false and you will see your custom message.
PS: $request->wantsJson() is not necessary if your clients send the correct header info, eg: 'accept:application/json'
You can remove $request->wantsJson
or you can set the header in your request "Accept" => "application/json"
May this can help you:
public function render($request, Exception $exception)
{
if ($exception instanceof ModelNotFoundException && ($request->wantsJson() || $request->ajax())) {
return response()->json(['message' => 'Not Found!'], 404);
}
return parent::render($request, $exception);
}

Manage 'MethodNotAllowedHttpException ' in RESTful APIs using Laravel 5.3

I am new to laravel and want to handle exception if a user hits a urls by using wrong HTTP method. I want to send user response in json but code is not working, sometimes it gives blanks page. Below is my code:
Handler.php
public function render($request, Exception $exception)
{
if ($exception instanceof MethodNotAllowedHttpException) {
return response()->json(['error' => 'Bad Request.'], 404);
}
}
Thanks in advance
try this:
public function render($request, Exception $exception)
{
if (basename(str_replace('\\', '/', get_class($exception))) == 'MethodNotAllowedHttpException') {
return response()->json(['error' => 'Bad Request.'], 404);
}
return parent::render($request, $exception);
}

form validation exception not catching by Exception in laravel 5.1?

In laravel5, I have catching all error at app/Exceptions/Handler#render function and it was working fine.
code given below,
public function render($request, Exception $e) {
$error_response['error'] = array(
'code' => NULL,
'message' => NULL,
'debug' => NULL
);
if ($e instanceof HttpException && $e->getStatusCode() == 422) {
$error_response['error']['code'] = 422;
$error_response['error']['message'] = $e->getMessage();
$error_response['error']['debug'] = null;
return new JsonResponse($error_response, 422);
}
}
return parent::render($request, $e);
}
But in laravel5.1,When form validation failes,it throws error message with 422exception. but it is not catching from app/Exceptions/Handler#render but working fine with abort(422).
How can I solve this?
You can catch simply by doing
public function render($request, Exception $e) {
if($e instanceof ValidationException) {
// Your code here
}
}
When Form Request fails to validate your data it fires the failedValidation(Validator $validator) method that throws HttpResponseException with a fresh Redirect Response, but not HttpException. This exception is caught via Laravel Router in its run(Request $request) method and that fetches the response and fires it. So you don't have any chance to handle it via your Exceptions Handler.
But if you want to change this behaviour you can overwrite failedValidation method in your Abstract Request or any other Request class and throw your own exception that you will handle in the Handler.
Or you can just overwrite response(array $errors) and create you own response that will be proceed by the Router automatically.

How to send Laravel error responses as JSON

Im just move to laravel 5 and im receiving errors from laravel in HTML page. Something like this:
Sorry, the page you are looking for could not be found.
1/1
NotFoundHttpException in Application.php line 756:
Persona no existe
in Application.php line 756
at Application->abort('404', 'Person doesnt exists', array()) in helpers.php line
When i work with laravel 4 all works fine, the errors are in json format, that way i could parse the error message and show a message to the user. An example of json error:
{"error":{
"type":"Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException",
"message":"Person doesnt exist",
"file":"C:\\xampp\\htdocs\\backend1\\bootstrap\\compiled.php",
"line":768}}
How can i achieve that in laravel 5.
Sorry for my bad english, thanks a lot.
I came here earlier searching for how to throw json exceptions anywhere in Laravel and the answer set me on the correct path. For anyone that finds this searching for a similar solution, here's how I implemented app-wide:
Add this code to the render method of app/Exceptions/Handler.php
if ($request->ajax() || $request->wantsJson()) {
return new JsonResponse($e->getMessage(), 422);
}
Add this to the method to handle objects:
if ($request->ajax() || $request->wantsJson()) {
$message = $e->getMessage();
if (is_object($message)) { $message = $message->toArray(); }
return new JsonResponse($message, 422);
}
And then use this generic bit of code anywhere you want:
throw new \Exception("Custom error message", 422);
And it will convert all errors thrown after an ajax request to Json exceptions ready to be used any which way you want :-)
Laravel 5.1
To keep my HTTP status code on unexpected exceptions, like 404, 500 403...
This is what I use (app/Exceptions/Handler.php):
public function render($request, Exception $e)
{
$error = $this->convertExceptionToResponse($e);
$response = [];
if($error->getStatusCode() == 500) {
$response['error'] = $e->getMessage();
if(Config::get('app.debug')) {
$response['trace'] = $e->getTraceAsString();
$response['code'] = $e->getCode();
}
}
return response()->json($response, $error->getStatusCode());
}
Laravel 5 offers an Exception Handler in app/Exceptions/Handler.php. The render method can be used to render specific exceptions differently, i.e.
public function render($request, Exception $e)
{
if ($e instanceof API\APIError)
return \Response::json(['code' => '...', 'msg' => '...']);
return parent::render($request, $e);
}
Personally, I use App\Exceptions\API\APIError as a general exception to throw when I want to return an API error. Instead, you could just check if the request is AJAX (if ($request->ajax())) but I think explicitly setting an API exception seems cleaner because you can extend the APIError class and add whatever functions you need.
Edit: Laravel 5.6 handles it very well without any change need, just be sure you are sending Accept header as application/json.
If you want to keep status code (it will be useful for front-end side to understand error type) I suggest to use this in your app/Exceptions/Handler.php:
public function render($request, Exception $exception)
{
if ($request->ajax() || $request->wantsJson()) {
// this part is from render function in Illuminate\Foundation\Exceptions\Handler.php
// works well for json
$exception = $this->prepareException($exception);
if ($exception instanceof \Illuminate\Http\Exception\HttpResponseException) {
return $exception->getResponse();
} elseif ($exception instanceof \Illuminate\Auth\AuthenticationException) {
return $this->unauthenticated($request, $exception);
} elseif ($exception instanceof \Illuminate\Validation\ValidationException) {
return $this->convertValidationExceptionToResponse($exception, $request);
}
// we prepare custom response for other situation such as modelnotfound
$response = [];
$response['error'] = $exception->getMessage();
if(config('app.debug')) {
$response['trace'] = $exception->getTrace();
$response['code'] = $exception->getCode();
}
// we look for assigned status code if there isn't we assign 500
$statusCode = method_exists($exception, 'getStatusCode')
? $exception->getStatusCode()
: 500;
return response()->json($response, $statusCode);
}
return parent::render($request, $exception);
}
On Laravel 5.5, you can use prepareJsonResponse method in app/Exceptions/Handler.php that will force response as JSON.
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Exception $exception
* #return \Illuminate\Http\Response
*/
public function render($request, Exception $exception)
{
return $this->prepareJsonResponse($request, $exception);
}
Instead of
if ($request->ajax() || $request->wantsJson()) {...}
use
if ($request->expectsJson()) {...}
vendor\laravel\framework\src\Illuminate\Http\Concerns\InteractsWithContentTypes.php:42
public function expectsJson()
{
return ($this->ajax() && ! $this->pjax()) || $this->wantsJson();
}
I updated my app/Exceptions/Handler.php to catch HTTP Exceptions that were not validation errors:
public function render($request, Exception $exception)
{
// converts errors to JSON when required and when not a validation error
if ($request->expectsJson() && method_exists($exception, 'getStatusCode')) {
$message = $exception->getMessage();
if (is_object($message)) {
$message = $message->toArray();
}
return response()->json([
'errors' => array_wrap($message)
], $exception->getStatusCode());
}
return parent::render($request, $exception);
}
By checking for the method getStatusCode(), you can tell if the exception can successfully be coerced to JSON.
If you want to get Exception errors in json format then
open the Handler class at App\Exceptions\Handler and customize it.
Here's an example for Unauthorized requests and Not found responses
public function render($request, Exception $exception)
{
if ($exception instanceof AuthorizationException) {
return response()->json(['error' => $exception->getMessage()], 403);
}
if ($exception instanceof ModelNotFoundException) {
return response()->json(['error' => $exception->getMessage()], 404);
}
return parent::render($request, $exception);
}

Categories