Hello, I would like to know if it is possible for me to transform Laravel's error json into this new json.
I'm using Laravel 7
{
"message": "The given data was invalid.",
"errors": {
"email": [
"email is already in use"
],
"username": [
"username is already in use"
]
}
}
to
{
"message": "The given data was invalid.",
"errors": {
"email": "email is already in use",
"username": "username is already in use"
}
}
Inside of your controller if you validate your POST request with the Validator facade you can convert the errors into a collection and map over them.
use Illuminate\Support\Facades\Validator;
// Faking the Request array & Commenting out to fail request
$input = [
// 'username' => 'username',
// 'password' => 'password',
];
$validator = Validator::make((array) $input, [
'username' => 'required|unique|string',
'password' => 'required|string',
]);
if ($validator->fails()) {
$formatted = collect($validator->errors())->map(function ($error) {
return $error[0];
});
return response()->json([
'message' => 'The given data was invalid.',
'errors' => $formatted,
], 422);
}
I'd propose a different approach to the problem.
In you User model you could add a class method called ValidationBook.
public static function ValidationBook($except = [], $append = [])
{
$book = ['rules' => [], 'messages' => []];
$book['rules'] = [
'user.email' => 'required|email|unique:users,email',
'user.password' => 'required|min:8',
'user.password_confirmation' => 'required|min:8|same:user.password',
];
$book['messages'] = [
'user.email.required' => 'The email is required',
'user.email.email' => 'The email must be a valid email address.',
'user.email.unique' => 'This email is already in use.',
'user.password.required' => 'A password is required.',
'user.password.min' => 'Password musst have at least 8 characters',
'user.password_confirmation.required' => 'The password confirmation is required.',
'user.password_confirmation.same' => 'Passwords doesn't match',
];
if (!empty($except)) {
$except = array_flip($except);
$book['rules'] = array_diff_key($book['rules'], $except);
}
if (!empty($append))
$book = array_merge_recursive($book, $append);
return $book;
}
Then, in the controller that receives the request you can simply do:
$vb = User::ValidationBook();
$vb["rules"]["user.client_secret"] .= $request->input("user")["client_id"];
$data = $request->validate($vb["rules"], $vb["messages"]);
Notice that you could define each of the errors, and if something has more than one issues, the response will send all the rules that failed.
Related
I have an array with two relevant keys where at least one of both shall contain a valid email address.
$data = [
'mail' => 'firstname.lastname#tld.com',
'mail2' => 'firstname.lastname#tld.com',
...
]
I've tried a validation using the exclude_with method, which works if the mail field is invalid, but mail2 is valid. However, it doesn't vice versa.
$validated = Validator::make($data, [
'mail' => 'exclude_with:mail|email',
'mail2' => 'exclude_with:mail2|email',
])->validate();
I could do this easily with other PHP methods or regular expressions, but I wonder if this is archivable with Laravel's validator.
The goal is to get at least one field with a valid email or fail.
Update
Based on Abdulla's promising answer, I found that even if the first email is valid but the second is not, the validation fails:
$data = [
'mail' => 'firstname.lastname#tld.com', // correct
'mail2' => 'firstname.lastname#tld.com' // wrong
];
$validator = Validator::make($data, [
'mail' => 'exclude_unless:mail2,null|email',
'mail2' => 'exclude_unless:mail,null|email',
]);
Output:
The mail2 must be a valid email address.
Use exclude_unless() in Laravel
It was tested with these two examples. (You can swap array positions too). And removed ->validate() as well
One valid and one invalid Email (as per in the question)
$data = [
'mail' => 'firstname.lastname#tld.com', // wrong
'mail2' => 'firstname.lastname#tld.com' // correct
];
$validator = Validator::make($data, [
'mail' => 'exclude_unless:mail2,null|email',
'mail2' => 'exclude_unless:mail,null|email',
]);
if ($validator->fails()) {
$messages = $validator->messages();
foreach ($messages->all() as $message)
{
echo $message;
}
die();
}
echo "pass";
die();
Output was
Both invalid emails
$data = [
'mail' => 'firstname.lastname#tld.com', // wrong
'mail2' => 'firstname.lastname#tld.com' // wrong
];
$validator = Validator::make($data, [
'mail' => 'exclude_unless:mail2,null|email',
'mail2' => 'exclude_unless:mail,null|email',
]);
if ($validator->fails()) {
$messages = $validator->messages();
foreach ($messages->all() as $message)
{
echo $message;
}
die();
}
echo "pass";
die();
Output
customize the error message to a standard message such as "At least one Email should be valid".
I have a contact form, with some field and i want to get error message based on the form field, i.e the error message for name, email, phone, subject and message
Here is what I get here:
XHRPOSThttp://127.0.0.1:8000/save
[HTTP/1.1 200 OK 137ms]
success false
errors [ "The name field is required.", "The email field is required.", "The phone field is required.", "The subject field is required.", "The description field is required." ]
because of this line in controller
$validator->errors()->all()
but I want the error message to be like:
errors:object{name:""The name field is required."
email:"The email field is required.", ...}
the controllers look like
$validator = Validator::make($request->all(), [
'name' => 'required|max:60',
'email' => 'required|email',
'phone' => 'required|min:10|numeric',
'subject' => 'required|max:100',
'description' => 'required|max:250',
]);
if ($validator->fails()) {
return response()->json([
'success' => false, 'errors' =>$validator->errors()->all()
]);
}
You probably want to use the default Laravel validation function (available in all controllers), which handles this output automatically:
// SomeController.php
$this->validate($request, [
'name' => 'required|max:60',
// ...
]);
When the validation fails, a ValidationException is thrown which should be automatically handled in your exception handler.
You can try with using FormRequest for validation and custom messages.
https://laravel.com/docs/8.x/validation#creating-form-requests
use Illuminate\Support\Facades\Validator;
$exampleRequest = new ExampleRequest();
$validator = Validator::make($request->all(), $exampleRequest->rules(), $exampleRequest->messages());
if($validator->fails()){
return response()->json($validator->errors(), 422);
}
This will return JSON response (for an API in this case):
{
"name": [
"First name is required."
]
}
For given rules and messages in ExampleRequest:
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
// 'name' => 'required',
];
}
public function messages()
{
return [
'name.required' => 'First name is required.'
];
}
I am facing the problem with custom validation messages in laravel.
I want to validate user create request, I have data as follows:
first_name:Akhsay
middle_name:R
last_name:Doe
gender:male
miscellaneous:{"dob":"","birth_name":"xyz"}
I have created the validation rules for creating a user in userCreateRequest.php as
public function rules()
{
return [
'first_name' => 'required',
'middle_name' => 'required',
'last_name' => 'required',
'gender' => 'required',
'miscellaneous' => 'json|validate_misc_info',
];
}
/**
* validation messages
*
* #return array
*/
public function messages()
{
return [
"first_name.required" => "First name is required.",
"middle_name.required" => "Middle name is required.",
"last_name.required" => "Last name is required.",
"gender.required" => "Gender is required.",
'miscellaneous.validate_misc_info' => '(**want to show specific error message here**)?'
];
}
For miscellaneous information, I have created a custom validation service provider and in boot method of custom validator I have written the validation code as
Validator::extend('validate_misc_info',function($attribute, $value, $params, $validator) {
$data = json_decode($value, true);
$rules = [
"dob" => "required|date",
"birth_name" => "required|min:2|max:50",
];
$messages= [
"dob.required" => "Date of birth is required",
"birth_name.required" => "Birth name is required",
];
$validator = $data ? Validator::make($data, $rules, $messages) : false;
if ($validator && $validator->fails()) {
return false;
}
return true;
});
But when I 'm using this validation rule in userCreateRequest.php as
public function rules()
{
return [
'first_name' => 'required',
'middle_name' => 'required',
'last_name' => 'required',
'initial' => 'required',
**'miscellaneous' => 'json|validate_misc_info',**
];
}
Its showing me the error as
{
"message": "The given data was invalid.",
"errors": {
"miscellaneous": [
"validation.validate_misc_info"
]
}
but I want to show a specific error message as
{
"message": "The given data was invalid.",
"errors": {
"miscellaneous": [
"Date of birth is required"
]
}
Please help me.
In my Laravel API, email validation error response comes like this...
{
"status": 409,
"message": {
"emailAddress": [
"A user with email: my#email.com already exists."
]
}
}
The message value comes from this : $validator->messages();
Now, what I want is to get the error response like this json format
{
"status": 409,
"message": "A user with email: my#email.com already exists"
}
How to get this done by going inside $validator->messages(); ?
If you only want to return the first error to your user, you can handled that by using the MessageBag as a Collection, like so:
$validator = Validator::make($request->input(), [
"email" => "...",
"password" => "..."
]);
if ($validator->fails()) {
$firstError = $validator->messages()->first();
return response()->json(["status" => 409, "message" => $firstError], 409);
}
For larval 5.6 and above you can use below solution.
Edit file under app/Exceptions/Handler.php and add following files
protected function convertValidationExceptionToResponse(ValidationException $e, $request) {
if ($e->response) {
return $e->response;
}
$errors = $e->validator->errors()->getMessages();
if ($request->expectsJson()) {
return response()->json(["errors" => $this->error_to_json($errors)], 422);
}
return redirect()->back()->withInput(
$request->input()
)->withErrors($errors);
}
protected function error_to_json($errors) {
$json_errors = $errors;
$new_errors = array();
foreach ($json_errors as $key => $value) {
$new_errors[$key] = $value[0];
}
return $new_errors;
}
Hope this help you:
$validator = Validator::make($request->all(), [
'email' => 'required|emails|exists:users',
]);
if ($validator->fails()) {
return response()->json(['status' => 409, 'message' => "A user with email: ' . $request->email . ' already exists"], 200);
}
I have a small question. I create simple API using Laravel. When I use validation and if it fails, I got a common message:
{
"result": false,
"message": "The given data failed to pass validation.",
"details": []
}
But how can I get details about which field fails and why like that:
{
"result":false,
"message":"The given data failed to pass validation.",
"details":{
"email":[
"The email field is required."
],
"password":[
"The password must be at least 3 characters."
]
}
}
My code in controller looks like this:
protected function validator(array $data)
{
$validator = Validator::make($data, [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:3',
]);
return $validator;
}
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
'role_id' => 2
]);
}
It is better to handle the validator within the same process, like this:
public function register(Request $request){
$validator = Validator::make($request->all(),[
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
]);
if($validator->fails()){
return response()->json([
"error" => 'validation_error',
"message" => $validator->errors(),
], 422);
}
$request->merge(['password' => Hash::make($request->password)]);
try{
$user = User::create($request->all());
return response()->json(['status','registered successfully'],200);
}
catch(Exception $e){
return response()->json([
"error" => "could_not_register",
"message" => "Unable to register user"
], 400);
}
}
You should make sure you're sending the request with the Accept: application/json header.
Without that - Laravel won't detect that it's an API request,
If validation fails, a redirect response will be generated to send the user back to their previous location. The errors will also be flashed to the session so they are available for display. If the request was an AJAX request, a HTTP response with a 422 status code will be returned to the user including a JSON representation of the validation errors.
check the documentation
I used validate in my project:
1.I created app/http/requests/CreateUserRequestForm.php
public function rules()
{
return [
"name" => 'required',
"address" => 'required',
"phnumber" => 'required|numeric',
];
}
public function messages()
{
return [
'name.required' => 'Please Enter Name',
'addresss.required' => 'Please Enter Address',
'phnumber.required' => 'Please Enter PhNumber'
];
}
call the RequestForm in controller
use App\Http\Requests\CreateUserRequestForm;
public function createUser(CreateUserRequestForm $request)
{
// create
$user= UserModel::create([
'name' => $request->input('name'),
'address' => $request->input('address'),
'phnumber' => $request->input('phnumber')
]);
return response()->json(['User' => $user]);
}
Try this i didn't try but it should be work for you.
You may use the withValidator method. This method receives the fully
constructed validator, allowing you to call any of its methods before
the validation rules are actually evaluated.
take reference from here. laravel validation
/**
* Configure the validator instance.
*
* #param \Illuminate\Validation\Validator $validator
* #return void
*/
public function withValidator($validator)
{
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add('email', 'Please enter valid email id');
}
});
}
Try this:
public function create(){
// ------ Validate -----
$this->vallidate($request,[
'enter code here`name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:3'
]);
// ------ Create user -----
$user = User::create(['name' => $request->name']);
return response()->json([
'message' => "success",
'data' => $user``
]);
}