Laravel Passport - Change default Unauthenticated response to custom one - laravel

Thank you in advance,
I am using laravel passport for API user authentication while if access_token is invalid then we are receiving response like below
{
"message": "Unauthenticated."
}
but I want that response like below
{
"code" : 0,
"message": "Unauthenticated."
"data" : [],
}

If you want to change how Laravel renders an error you can do it in your app/Exceptions/Handler.php class.
In this particular case you can override the unauthenticated method by adding te following to your Handler class:
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json([
'message' => $exception->getMessage(),
'code' => 0,
'data' => [],
], 401);
}
return redirect()->guest($exception->redirectTo() ?? route('login'));
}

Related

Changing default error message when record not found - Laravel API

I am building a simple API, which there is a point that when the ID entered in the endpoint URL does not point to a valid record, I get a standard NotFoundHttpException. And I cannot figure out how to override this in order to provide my own error message response as I do not wish to share my Model name etc.
Endpoint
Route::get('{mrl}', [MrlController::class, 'show']);
Controller
public function show(Mrl $mrl)
{
if ($data = $mrl) {
return response(['status' => 'ok', 'data' => $data], 200);
} else {
return response(['status' => 'error', 'message' => 'Could not retrieve data'], 500);
}
}
When I run this when a record exists I receive the following which is what I expect.
{
"status": "ok",
"data": {
"id": 98,
"market_id": 1,
"crop_id": 2,
"chemical_id": 113,
"maximum_residue_level": null,
"exempt": 0,
"comments": null,
"date_verified": "2021-10-07",
"created_at": "2021-10-19T05:42:12.000000Z",
"updated_at": "2021-10-19T05:42:12.000000Z"
}
}
However, when I enter an ID in the route endpoint for a record that does not exist, I receive the following:
{
"message": "No query results for model [App\\Seasonal\\Mrl] 99"
}
This is happening from what I understand to be the auto find of the record between the Route and the controller, and I am lost as to how to customize this behavior.
Thanks in advance for your help!
you don't show the code where you are fetchning the model from the database but we can assume something like that:
$mrl = Mrl::findOrFail($id);
show($mrl);
The model findOrFail() method throws an exception when the model is not found, which is convenient when you want to adapt the response.
You can imagine something like that:
try {
$mrl = Mrl::findOrFail($id);
return response(['status' => 'ok', 'data' => $data], 200);
} catch (ModelNotFoundException $e) {
return response(['status' => 'error', 'message' => 'Could not retrieve data'], 500);
}
The idea is to catch the error thrown by your model to change the message and status code of the response.
When building APIs you should event add a "generic" catch statement for any unhandled errors to display a standardized generic error message and log what happened, like this:
try {
$mrl = Mrl::findOrFail($id);
// Do more things that could generate errors ?
return response(['status' => 'ok', 'data' => $data], 200);
} catch (ModelNotFoundException $e) {
// Not found
return response(['status' => 'error', 'message' => 'Could not retrieve data'], 500);
} catch (\Exception $e) {
// Generic error
\Log::error($e);
return response(['status' => 'error', 'message' => 'An error occured'], 500);
}
After spending time reading the docs I finally found the answer on how to customize the behaviour if a record is found when utilising Eloquents Route Model Binding.
In the Laravel docs, there is a method for this explicit purpose, to override the default behaviour when the bound model does not have a valid record.
The method for doing this is to chain the ->missing() function call to the end of your route and then providing the behaviour for the response you wish to provide. As below:
Route::get('{mrl}', [MrlController::class, 'show'])->missing(function () {
return response(['status' => 'error', 'message' => 'Invalid query.'], 404);
});
Chaining this method onto my request has enabled me to return the generic response I was hoping for when querying an invalid model record.

change the format of laravel API Errors and Exceptions

I write api for the applications with laravel.
for example I have two field which are "city_id" and "address" and I validate them with these rules :
$request->validate([
'city_id' => 'bail|required|numeric',
'address' => 'required'
]);
if validation fails the response will be :
{
"message": "The given data was invalid.",
"errors": {
"city_id": ["The city id field is required."]
}
}
everything is fine but I want change the validation error at api response to this :
{
"msg" => 'The city id field is required.'
}
actually I want send one error without the key . where can I change that?
You can write/modify the Laravel exceptions handler. Here you can read more about it here https://laravel.com/docs/5.8/errors or here https://laravel.com/docs/6.x/errors (depends what version of Laravel you using)
Example:
class Handler extends ExceptionHandler
{
...
public function render($request, Exception $e)
{
if ($exception instanceof ValidationException) {
return new JsonResponse(
['msg' => $e->getMessage()],
400
);
}
}
...
}

The PUT method is not supported for this route. Supported methods: GET, HEAD, POST

I have the following code in my controller:
public function update(Request $request, $id)
{
$cook = cooks::findOrFail($id);
if (!$cook) {
return response()->json([
'success' => false,
'message' => 'Sorry, cook with id ' . $id . ' cannot be found',
], 400);
}
$updated = $cook->fill($request->all())
->save();
if ($updated) {
return response()->json([
'success' => true,
]);
} else {
return response()->json([
'success' => false,
'message' => 'Sorry, cook could not be updated',
], 500);
}
}
And when I use in my postman method PUT I received this message "The PUT method is not supported for this route. Supported methods: GET, HEAD, POST."
in my api.php I have the following line:
Route::resource('cook', 'cookList');
and here is the route that I use in postman:
`http://127.0.0.1:8000/api/cook`
with body id-1 and title-cook
Can someone help me, please?
You are missing a parameter in your route. As you are using http://127.0.0.1:8000/api/cook it's guessing you are trying to go to the index method or store method. So add a id parameter to your route and it should work with PUT method.
http://127.0.0.1:8000/api/cook/1
(Not tested, but should work)
You could try the Form Method Spoofing:
https://laravel.com/docs/5.8/routing#form-method-spoofing

Laravel : Validation not working when testing on live

Create a user validate function with validation in API integration When i try to validate user with some validation and check it in postman it is working perfect in local machine but when i uploaded code on server and test, it is not working.
Controller function :
public function confirmUser(ForgotPasswordRequest $request)
{
// ForgotPasswordRequest for validate
$user = User::leftjoin('user_details','users.id', '=', 'user_details.user_id')
->where('user_details.phone', '=', $request->post('phone'))
->where('users.email', '=', $request->post('email'))
->first();
if(!$user) {
return response()->json([
'message' => "The credentials you provided cannot be determined to be authentic.!!",
'status_code' => 404,
]);
}
$token = JWTAuth::fromUser($user);
return response()->json([
'message' => "Your account is eligible for change password.!!",
'token' => $token,
'status_code' => 200
]);
}
My forgotPasswordRequest.php code :
<?php
namespace App\Api\V1\Requests;
use Config;
use Dingo\Api\Http\FormRequest;
class ForgotPasswordRequest extends FormRequest
{
public function rules()
{
return Config::get('boilerplate.forgot_password.validation_rules');
}
public function authorize()
{
return true;
}
}
And in config folder boilerplate.php file contain forgot_password rules :
'forgot_password' => [
'validation_rules' => [
'email' => 'required|email',
'phone' => 'required|min:11|numeric'
]
],
When email and phone null it returns only email validation not phone:
{
"error": {
"message": "422 Unprocessable Entity",
"errors": {
"email": [
"The email field is required."
]
},
"status_code": 422
}
}
What i am doing wrong ? It is related to cookies ?
There is nothing going wrong here.
Laravel checks whether the email field is properly filled in. It isn't, Laravel breaks out of the validation method and returns the exception.
If you fill in the email field, but leave the phone field blank, then the validation response will be about the phone field.

Creating Password Reset Function without using Laravel make:auth

I'm dealing with Laravel 5.6. I am using JWT Authentication, and I create my own authentication controller.
This is my recover method at AuthController,
public function recover(Request $request)
{
$user = User::where('email', $request->email)->first();
if (!$user) {
$error_message = "Your email address was not found.";
return response()->json(['success' => false, 'error' => ['email'=> $error_message]], 401);
}
try {
Password::sendResetLink($request->only('email'), function (Message $message) {
$message->subject('Your Password Reset Link');
});
} catch (\Exception $e) {
$error_message = $e->getMessage();
return response()->json(['success' => false, 'error' => $error_message], 401);
}
return response()->json([
'success' => true, 'data'=> ['message'=> 'A reset email has been sent! Please check your email.']
]);
}
In postman, if I execute the recover method, I get this message
{
"success": false,
"error": "Route [password.reset] not defined."
}
How can I deal with this. thanks!
You need to give the route a name, in this case password.reset. In your routes.php (or wherever you've defined them) call the name method:
Route::post('/password/reset', 'AuthController#recover')->name('password.reset');
If you haven't run make:auth you don't have the route defined, as the error itself is saying.
Try to define the following route in routes/web.php
Route::post('/pwdreset', 'AuthController#recover')
->name('password.reset');

Resources