I am trying to write a custom message for a validation in laravel.
I have checked online and I saw some post where others solve that same issue by adding a protected function. I have also added the function to my code but it is not working. This is my code
This is myFormController.php:
public function req(RegistrationRequest $request){ $validated =
$request->validated();
return $validated; )}
This is the RegistrationRequest.php:
use Illuminate\Contracts\Validation\Validator; use
Illuminate\Http\Exceptions\HttpResponseException;
public function authorize()
{
return true;
}
public function rules()
{
return [
'email' => 'required|email',
'firstname' => 'required|string|max:20',
'lastname' => 'required|string|max:50',
'password' => 'required|min:8',
];
} protected function failedValidation(Validator $validator) {
throw new HttpResponseException(response()->json($validator->errors(), 422)); }
When that did not work, I used this:
protected function
failedValidation(\Illuminate\Contracts\Validation\Validator
$validator) { throw new
\Illuminate\Validation\ValidationException(response()->json($validator->errors(),
422)); }
Please what am I doing wrongly?
If you want custom messages just override messages method you just need to return an array containing key value pairs of field_name => 'message'
/**
* Get custom messages for validator errors.
*
* #return array
*/
public function messages()
{
return [
'field_name.required' => 'field_name is requeired',
'field_name.max' => 'max length should be something.'
];
}
Related
Request Class
class LoginRequest extends FormRequest
{
public function wantsJson() {
return true;
}
public function authorize() {
return true;
}
public function rules() {
$validators = [
'email' => 'required',
'password' => 'required'
];
return $validators;
}
public function failedValidation(\Illuminate\Contracts\Validation\Validator $validator) {
if($validator->fails()) {
//print_r($validator->errors());
//die();
}
return parent::failedValidation($validator);
}
}
I have an api written in Laravel. I am trying to test the validation through Postman extension. When I submit some values of email and password, it works. I get the message that the credentials exists or not.
In case, I don't submit the values, then, there is no json messagebag returned.
I can confirm that there are validation error messages in MessageBag. Here is the screenshot. If the screenshot is not clear then please click it see it.
Another strange things is that the status code returned is 200
Please let me know if you need more info
In my situation I setup my Laravel API like this.
in my App\Exceptions\Handler
public function render($request, Exception $exception)
{
// return parent::render($request, $exception);
$rendered = parent::render($request, $exception);
if ($exception instanceof ValidationException) {
$json = [
'error' => $exception->validator->errors(),
'status_code' => $rendered->getStatusCode()
];
} elseif ($exception instanceof AuthorizationException) {
$json = [
'error' => 'You are not allowed to do this action.',
'status_code' => 403
];
}
else {
// Default to vague error to avoid revealing sensitive information
$json = [
'error' => (app()->environment() !== 'production')
? $exception->getMessage()
: 'An error has occurred.',
'status_code' => $exception->getCode()
];
}
return response()->json($json, $rendered->getStatusCode());
}
also import this on top
use Illuminate\Validation\ValidationException;
use Illuminate\Auth\Access\AuthorizationException;
It helps to format the errors into JSON format.
My LoginRequest looks like this (simple)
class LoginRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'email' => 'required|email',
'password' => 'required'
];
}
}
I have the controllers below to allow the user login with laravel auth system but when the user clicks in the button "Login" I get the following error:
Argument 1 passed to Illuminate\Auth\SessionGuard::attempt() must be of the type array, object given, called in C:\laragon\www\AGRIAPP\projet investisseur\AgriApp_Investor\AgriAppInvestor\vendor\laravel\framework\src\Illuminate\Foundation\Auth\AuthenticatesUsers.php on line 82
When I refresh the page I log in so I wanted to solve this problem
According to the documentation, the attempt function takes an array and a bool
LoginController.php
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function showLoginForm()
{
return view('auth.login');
}
protected function credentials(Request $request)
{
$credentials = array(
'slug' => $request->slug,
'password' => $request->password,
'statut' => 1,
);
if(Auth::attempt( $credentials,false ))
{
return Redirect::to( '/admin/home' );
}
}
public function username()
{
return 'slug';
}
protected function authenticated()
{
$user = auth()->user();
$user->online = true;
$user->save();
if ($user->rule->pluck( 'name' )->contains( 'abonne' )) {
return Redirect::to( '/admin-dashboard' );
}
return Redirect::to( '/admin/home' );
}
public function logout()
{
$user = Auth::user();
$user->online=false;
$user->save();
Auth::logout();
return redirect('/');
}}
AuthController.php
protected function attemptLogin(Request $request)
{
return $this->guard()->attempt(
$this->credentials($request), $request->filled('remember')
);
}
/**
* Get the needed authorization credentials from the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
protected function credentials(Request $request)
{
return $request->only($this->username(), 'password');
}
You have overridden the credentials() method but you're not returning anything from it.
Change your credentials method to:
protected function credentials(Request $request)
{
return [
'slug' => $request->slug,
'password' => $request->password,
'statut' => 1,
];
}
I realise that you were trying to authenticate the user inside the credentials method but you don't need to as, in this case, the method calling it is doing the same.
The reason your redirect didn't work either is because the calling method wasn't returning it, so your user was getting logged in but you were actually passing the redirect response to the attempt method which is what caused your error.
Also, I'm not sure if statut is a typo or not?
If you're using laravel 8+ all you have to do is to modify your credential function
protected function credentials(Request $request)
{
if(Auth::attempt($request->all())) {
return Redirect::to( '/admin/home' );
}
}
im having problems with error handler in my backend laravel api, don't show error message from validation.
routes/api
<?php
Route::group([
'middleware' => 'api',
], function ($router) {
Route::post('access/sign-up', 'AuthenticationController#signUp');
});
AuthenticationController
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
use App\Http\Requests\SignUpRequest;
use Illuminate\Http\Request;
use App\User;
class AuthenticationController extends Controller
{
/**
* Create a new AuthenticationController instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth:api', ['except' => ['signUp']]);
}
/**
*
*
* #return \Illuminate\Http\JsonResponse
*/
public function signUp(SignUpRequest $request)
{
//User::create($request->all());
return response()->json([
'data' => 'Usuario creado correctamente.'
]);
}
}
SignUpRequest
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class SignUpRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'email' => 'required|email|unique:users',
'firstName' => 'required',
'password' => 'required',
];
}
}
The thing is that when by postman i send password in blank or not send mail for example it send me to main page insted of sending me a json with all the errors like before. I don't know what to do.
I tryed with custom message in SignUpRequest, but that's not the problem, think some kind of redirect in error handler.
You need to check just one setting must add Accept Type in header data in Postman
Accept : application/json
that is work in my case...
Just add that code to SignUpRequest
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;
protected function failedValidation(Validator $validator)
{
throw new HttpResponseException(response()->json($validator->errors(), 422));
}
Using the Form request; If validation fails, a redirect response will be generated to send the user back to their previous location. That's why you are redirecting back to the page instead of the response JSON.
Laravel have one protected method "failedValidation" method. Overwrite this method in your form request class.
protected function failedValidation(\Illuminate\Contracts\Validation\Validator $validator)
{
throw new \Illuminate\Validation\ValidationException(response()->json($validator->errors(), 422));
}
Update for laravel 8, the first parameter in ValidationException is the Validator class:
protected function failedValidation(Validator $validator)
{
throw new ValidationException($validator, response()->json($validator->errors(), 422));
}
TL;DR Add the following header: Accept: application/json
As mentioned by a few users over here, by default, when a Form Request fails, the application will attempt to redirect the user back to their previous location. That's why you're receiving a webpage instead of a JSON response.
We can also override the "failedValidation" method. But I would recommend setting the following header on the request Accept: application/json.
Laravel will return the appropriate response based on Accept header. For application/json Laravel will return a JSON response with form errors.
Simply, in your App\Exceptions\Handler, you have to register your custom exception handling in register() method:
public function register() {
$this->renderable( function ( ValidationException $ex, $request ) {
$response = [
'ErrorCode' => 'my_error_code',
'ErrorMessage' => $ex->validator->errors()
];
return response()->json( $response );
} );
}
add this method to your formRequest class. It works in laravel 9
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
class PostRequest extends FormRequest
{
protected function failedValidation(Validator $validator)
{
throw new HttpResponseException(response()->json([
'success' => false,
'message' => 'Validation errors',
'data' => $validator->errors(),
]));
}
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
switch ($this->method()) {
case 'GET':
case 'DELETE':{
return [];
}
case 'POST':{
return [
'title' => 'string|unique:posts|required',
'body' => 'required',
'image' => 'string|nullable',
];
}
case 'PUT':{
return [
'title' => 'string|unique:posts|required',
'body' => 'required',
'image' => 'string|nullable',
];
}
}
}
}
Just add that code to App\Exceptions\Handler:
public function render($request, Exception $exception)
{
if ($exception instanceof ValidationException) {
return response()->json([
'status' => false,
'error' => [
'type' => 'form',
'code' => 400,
'description' => 'Bad request.',
'detail' => $exception->validator->errors()
]
], 422);
}
return parent::render($request, $exception);
}
I am developing a Web application using Laravel. What I am doing now is creating a FirmRequest for the validation.
This is my FormRequest.
use Illuminate\Foundation\Http\FormRequest;
class StoreVacancy extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'title' => 'required',
'type' => 'required',
'complex_field' => ...need complex conditional validation based on the type field
];
}
}
If I did not use the FormRequest, I can create validator in the controller and set complex conditional validation rule like this.
$v = Validator::make($data, [
//fields and rules
]);
$v->sometimes('reason', 'required|max:500', function ($input) {
return $input->games >= 100;
});
But the issue is that I am not creating the Validator in the controller. But I am using the FormRequest. How can I achieve the same thing in the FormRequest?
You can manually adjust the rules depending on the input data:
class StoreVacancy extends FormRequest
{
public function rules()
{
$reason = $this->request->get('reason'); // Get the input value
$rules = [
'title' => 'required',
'type' => 'required',
];
// Check condition to apply proper rules
if ($reason >= 100) {
$rules['complex_field'] = 'required|max:500';
}
return $rules;
}
}
Its not the same as sometimes, but it does the same job.
Since 5.4 you can use the method "withValidator" inside your FormRequest:
https://laravel.com/docs/5.4/validation
This method receives the fully constructed validator, allowing you to call any of its methods before the validation rules are actually evaluated
use Illuminate\Foundation\Http\FormRequest;
class StoreVacancy extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'title' => 'required',
'type' => 'required',
];
}
public function withValidator($validator)
{
$validator->sometimes('reason', 'required|max:500', function ($input) {
return $input->games >= 100;
});
}
}
You can check the createDefaultValidator function in https://github.com/laravel/framework/blob/5.7/src/Illuminate/Foundation/Http/FormRequest.php. We will override that function and add our condition
/**
* Add Complex Conditional Validation to the validator instance.
*
* #param \Illuminate\Validation\Factory $factory
* #return \Illuminate\Validation\Validator
*/
public function validator($factory)
{
$validator = $factory->make(
$this->validationData(),
$this->container->call([$this, 'rules']),
$this->messages(),
$this->attributes()
);
$validator->sometimes('reason', 'required|max:500', function ($input) {
return $input->games >= 100;
});
return $validator;
}
I have a login functionality from Web and also from API. I have created one Request file where I have written rules for this. For web, it is working perfectly and given output as expected but when I use it in API controller it redirects me to the login page, it should return JSON response.
One more thing, I want to add extra parameter "status" as it is failed or succeeds.
Here is my code
Request File
public function rules()
{
return [
'username' => 'required',
'password' => 'required'
];
}
API controller
public function login(Request $request)
{
$response = array();
$validator = Validator::make($request->all(), [
'username' => 'required',
'password' => 'required'
]);
if ($validator->fails()) {
$response['status'] = false;
$response['message'] = $validator->messages();
return Response::json($response);
}
try {
$username = trim($request->username);
$password = trim($request->password);
$isAuth = $this->userRepository->login($username, $password);
if ($isAuth) {
$user = Auth::user();
$response['status'] = true;
$response['message'] = Lang::get('custom.auth_success');
$response['user_detail'] = $user;
} else {
$response['status'] = false;
$response['message'] = Lang::get('auth.failed');
}
} catch (\Exception $e) {
$response = array();
$response['status'] = false;
$response['message'] = Lang::get('custom.something_wrong');
}
return Response::json($response);
}
and Web controller
public function checkAuth(UserAuthenticate $request)
{
try {
$username = trim($request->username);
$password = trim($request->password);
$isRemember = false;
if (isset($request->remember) && $request->remember == 'on') {
$isRemember = true;
}
$isAuth = $this->userRepository->login($username, $password, $isRemember);
if ($isAuth) {
return redirect('programs');
} else {
return redirect('login')->withInput()->withErrors(['username' => Lang::get('auth.failed')]);
}
} catch (\Exception $e) {
return redirect('login')->withInput()->withErrors(['error' => Lang::get('custom.something_wrong')]);
}
}
Route/web.php
Route::group(['middleware' => ['guest']], function () {
Route::get('login', ['as' => 'login', 'uses' => 'Front\UserController#login']);
});
Route/api.php
Route::post('user/authenticate', 'API\UserController#login');
I looked for the solutions but didn't found anything
Edit: if you want to use extends Request for both validators do the web validation through ajax
Since you're using passport you already have the token so you can skip login
For api your validator needs to extend Request instead of FormRequest
You can't use the same validator, because the web validator extends FormRequest and that return html. Two validators are necessary, there is no way around it.
use App\Http\Requests\Request;
class YourApiRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{}....
In your normal web request you would have
use Illuminate\Foundation\Http\FormRequest;
class YourWebRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return \Auth::check();
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{....
In Handler.php you need to add something to the render method (if you return json from your api)
If you do not prefix your routes with api/ then figure out how to check if you are in api
if (strpos($prefix, 'api') !== false) {
if ($exception instanceof ValidationException) {
return response()->json(['success' => false, 'error' => $exception->errors(), 'data' => null], 200);
}
return response()->json(['success' => false, 'error' => $exception->getMessage(), 'data' => null], 200);
}
You may try to over ride the Laravel form request validation's failedValidation() method.
public function failedValidation(Validator $validator)
{
//wantsJson() that checks Accept header of the request and returns TRUE if JSON was requested.
if ($this->wantsJson()) {
throw new HttpResponseException(response()->json(["response" => [
'msg' => $validator->errors()->all(),
]]));
}
}
[Not tested on api calls]