How to display custom vaildation error messages for API requests? - php

try{
$request->validate([
'aadhar' => 'required|digits:12|numeric',
'name' => 'required|string|max:511',
'dob' => 'required|date_format:Y-m-d',
'email' => 'required|email|max:255',
'address' => 'required|string',
'insuranceid' => 'required|digits_between:1,15|integer',
'password' => 'required|min:59|max:60',
]);
}
catch(Exception $error){
$message = $error->getMessage();
$status_code=400;
return response()->json(["message" => $message,"status_code" => $status_code]);
}
This is my piece of code for the validation of the request parameters sent to an API. The documentation gives details only about custom error messages in case of a form request.
The validation errors give the default message "The given data was invalid" but I would like to know which of the parameter was invalid. How do I give custom validation error messages for API requests validation?

First of all, to decouple your code, you could use a Form Request class. From the docs:
For more complex validation scenarios, you may wish to create a "form
request". Form requests are custom request classes that contain
validation logic.
This class contains two methods:
1 - rules, the place where you specify your rules, it should return an array of rules.
2 - authorize that return a boolean,this method control who is allowed to perform this request. By default is set to false, so every call will be rejected.
So, in your case, it should be something like this:
First, create your custom Request class executing this artisan command in your console:
php artisan make:request CreateCustomObjectRequest
This wil create a new class under app/Http/Requests:
class CreateCustomObjectRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// Implement here your Auth validation, something like:
return auth()->check();
// or just return "true" if you want to take care of this anywhere else.
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'aadhar' => 'required|digits:12|numeric',
'name' => 'required|string|max:511',
'dob' => 'required|date_format:Y-m-d',
'email' => 'required|email|max:255',
'address' => 'required|string',
'insuranceid' => 'required|digits_between:1,15|integer',
'password' => 'required|min:59|max:60',
];
}
}
And then, in your controller, instead of inject a regular Request object, we are gonna use this custom Request object:
use App\Http\Requests\CreateCustomObjectRequest;
// ...
public function store(CreateCustomObjectRequest $request)
{
// the rest of your controller logic.
}
Now, the part you are really interested in. To return errors in a json way you should add the next header when making a request:
Accept: Application/json
This header will tell Laravel that the output should be a json response, so it will convert it to json. Note that this will only work with the validation rules and when returning objects like return $someObject. To more further customization you shoud use something like:
return response()->json(['data' => $someObject], 200);

$validator = Validator::make($request->all(), [
'password' => [
'required',
'confirmed',
'between:8,55'
]
]);
if ( $validator->fails() ) {
return response()->json( [ 'errors' => $validator->errors() ], 400 );
}

Related

Laravel validate request parameter only if it's availale

I implement laravel API, for validation I created a separate request file, and I write my validation rules in that and it's working fine. But the issue is I want to validate my request parameter only if it's available in request. Here is my code for that.
UserFormRequest.php
public function rules() {
return [
'customer_phone' => 'regex:/^([0-9\s\-\+\(\)]*)$/|max:15',
'customer_email' => 'required|email',
]
}
You can use the conditional validation using sometimes:
public function rules() {
return [
'customer_phone' => 'regex:/^([0-9\s\-\+\(\)]*)$/|max:15',
'customer_email' => 'sometimes|required|email',
]
}
In the example above, the customer_email field will only be validated if it is present.

Laravel: Custom validation messages in Custom Form Requests

I am trying to keep my controller clean and move the custom request validation in to a separate class as:
public function register(RegisterUserRequest $request)
and in there define all the usual functions, such as
public function rules(),
public function messages(), and
public function authorize()
However, the frontend is expecting the following data to display:
title (title related to the validation error message), description (which is the the actual validation error message), and status (=red, yellow etc)
How can I actually customise the response of the request?
Something like this, does not seem to be working:
protected function failedValidation(\Illuminate\Contracts\Validation\Validator $validator)
{
$response = new Response(['data' => [],
'meta' => [
'title' => 'Email Invalid'
'description' => '(The error message as being returned right now)',
'status' => 'red'
]);
throw new ValidationException($validator, $response);
}
Any ideas?
you can do this by making request in laravel as the following :
php artisan make:request FailedValidationRequest
this command will create class called FailedValidationRequest in
App\Http\Request directory and you cab write your rules inside this class as the following:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class FailedValidationRequest 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 [
'title' => 'required'
'description' => 'required',
'status' => 'required|numeric'
];
}
}
and if you want to customize the error message you can download the language you want from this link using composer:
https://packagist.org/packages/caouecs/laravel-lang
and write the language you want by copying the languge folwder to the lang directory in your resource folder.
'custom' => [
'title' => [
'required' => 'your custom message goes here',
],
'decription' => [
'required' => 'your custom message goes here',
],
],

Send custom response from validator in Laravel

I have a register user route which takes name , email and password. It works perfectly fine if the data is correct i.e. unique email and params are present, but if the user is already registered then Laravel sends auto error message in its own format. I want return format to be consistent in case of success or failure.
Successful Register return data:
{
"status": "success",
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjUsImlzcyI6Imh0dHA6Ly8xMjcuMC4wLjE6ODAwMC9hcGkvYXV0aC9yZWdpc3RlciIsImlhdCI6MTUyMTI3NTc5MiwiZXhwIjoxNTIxMjc5MzkyLCJuYmYiOjE1MjEyNzU3OTIsImp0aSI6Ik1wSzJSYmZYU1dobU5UR0gifQ.fdajaDooBTwP-GRlFmAu1gtC7_3U4ygD1TSBIqdPHf0"
}
But in case of error it sends data in other format.
{"message":"The given data was invalid.","errors":{"email":["The email has already been taken."]}}
I want both of them to be consistent. Success return data is fine. But i want to customize data if failure occurs. Something like this:
{"status":"error","message":"The given data was invalid.","errors":{"email":["The email has already been taken."]}}
Basically, I need status param to be coming with every response.
Also, I had one query while using Postman the output was pure HTML when error occurred the HTML page was default Laravel Page on the other hand when angular sends the same request the error is json format which i just pasted above.
Since angular is getting JSON respose in any case it is fine for me. But why didn't postman showed me that response.
Register Controller:
public function register(RegisterRequest $request)
{
$newUser = $this->user->create([
'name' => $request->get('name'),
'email' => $request->get('email'),
'password' => bcrypt($request->get('password'))
]);
if (!$newUser) {
return response()->json(['status'=>'error','message'=>'failed_to_create_new_user'], 500);
}
return response()->json([
'status' => 'success',
'token' => $this->jwtauth->fromUser($newUser)
]);
}
Register Request Handler:
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required',
'email' => 'required | email | unique:users,email',
'password' => 'required'
];
}
If I understand you correctly, you always get the error-response without the 'status' key.
What happens with your current code, are a couple of things:
RegisterController#register(RegisterRequest $request) is called by a route
Laravel sees you use the RegisterRequest class as an argument, and will instantiate this class for you.
Instantiating this class means it will directly validates the rules.
If the rules are not met, laravel directly responds with the errors found.
This response will always be in laravel's default 'layout' and the code stops there.
Conclusion: Your code is not even triggered when your validation rules are not met.
I've looked into a solution and came up with this:
public function register(Illuminate\Http\Request $request)
{
//Define your validation rules here.
$rules = [
'name' => 'required',
'email' => 'required | email | unique:users,email',
'password' => 'required'
];
//Create a validator, unlike $this->validate(), this does not automatically redirect on failure, leaving the final control to you :)
$validated = Illuminate\Support\Facades\Validator::make($request->all(), $rules);
//Check if the validation failed, return your custom formatted code here.
if($validated->fails())
{
return response()->json(['status' => 'error', 'messages' => 'The given data was invalid.', 'errors' => $validated->errors()]);
}
//If not failed, the code will reach here
$newUser = $this->user->create([
'name' => $request->get('name'),
'email' => $request->get('email'),
'password' => bcrypt($request->get('password'))
]);
//This would be your own error response, not linked to validation
if (!$newUser) {
return response()->json(['status'=>'error','message'=>'failed_to_create_new_user'], 500);
}
//All went well
return response()->json([
'status' => 'success',
'token' => $this->jwtauth->fromUser($newUser)
]);
}
Now, not conforming your validation rules still triggers an error, but your error, and not laravel's built-in error :)
I hope it helps!
In Laravel 8 I added my custom invalidJson with the "success": false:
in app/Exceptions/Handler.php:
/**
* Convert a validation exception into a JSON response.
*
* #param \Illuminate\Http\Request $request
* #param \Illuminate\Validation\ValidationException $exception
* #return \Illuminate\Http\JsonResponse
*/
protected function invalidJson($request, ValidationException $exception)
{
return response()->json([
'success' => false,
'message' => $exception->getMessage(),
'errors' => $exception->errors(),
], $exception->status);
}
This is what i came up with:
function validate(array $rules)
{
$validator = Validator::make(request()->all(), $rules);
$errors = (new \Illuminate\Validation\ValidationException($validator))->errors();
if ($validator->fails()) {
throw new \Illuminate\Http\Exceptions\HttpResponseException(response()->json(
[
'status' => false,
'message' => "Some fields are missing!",
'error_code' => 1,
'errors' => $errors,
], \Illuminate\Http\JsonResponse::HTTP_UNPROCESSABLE_ENTITY));
}
}
Create a helper directory (App\Helpers) and add it into a file. don't forget to add that into your composer.json
"autoload": {
"files": [
"app/Helpers/system.php",
],
},
Now you can call validate() in your controllers and get what you want:
validate([
'email' => 'required|email',
'password' => 'required|min:6|max:32',
'remember' => 'nullable|boolean',
'captcha' => 'prod_required|hcaptcha',
]);

Laravel 5.3: Form Validation does not show errors

I am trying to create a register form using Laravel.
I created a request \App\Http\Requests\RegisterNewUserRequest. This is the rules() method:
public function rules()
{
return [
'email' => 'required|email|min:6|max:255|unique:members',
'password' => 'required|min:6|max:16|confirmed',
'name' => 'required|min:2|max:255|alpha',
'surname' => 'required|min:2|max:255|alpha',
];
}
This is my Membership Controller
//Route::post('{locale}/create-new-user, 'MemberController#create_new_user');
public function create_new_user($locale, RegisterNewUserRequest $request)
{
$input = $request->all();
$input['ip'] = Request::ip();
Member::create($input);
return redirect("/$locale/create-account");
}
I violate validation rules while entering information. For example, I enter two different passwords, and enter 1 character to the email field. It does not say anything about it. Also It does not save the data into database. The page is redirected to same empty register form again.
I have got a validation summary in my view
...
#foreach($errors->all() as $e)
<li>{{$e}}</li>
#endforeach
...
I trace data posted. It is posted. But something is weird in flow.
EDIT
This happens also in my contact form. If I fill the contact form properly, it sends an e-mail. But if I violate the validation rules, it doesn't say anything about validation and not send e-mail.
This is my Contact page controller
/**
* #param Requests\SendMessageRequest $
*/
public function sendMessage($locale, SendMessageRequest $request)
{
// validation
// $this->validate($request,
// ['name' => 'required|min:3',
// 'email' => 'required|min:5',
// 'subject' => 'required|min:3',
// 'message' => 'required|min:15'
// ]);
$formData = $request->all();
$formData['ip'] = Request::ip();
Mail::send('contact.send', compact('formData'),
function ($message) use ($formData) {
$message->from('frommail#example.com', 'Example')
->bcc(['bccmail#example.com'])
->to('tomail#example.com')
->subject($formData['subject']);
}
);
}
\App\Http\Requests\SendMessageRequest file's rules() method
public function rules()
{
return [
'name' => 'required|min:3',
'email' => 'required|min:5',
'subject' => 'required|min:3',
'message' => 'required|min:15',
];
}
Actually it was working before. After adding multi language feature validation did not worked. I do not know if there is any relation.
I suspect about use statements at the top of controllers and requests.

Validation - Returning the first error for an AJAX response

I'm probably over complicating things where it's not needed, but I have a form that is submitted via AJAX and then validated. I'm trying to return the first error that occurs, but I can only ever seem to fetch validation.required which of course is useless to me; I can't tell the user which field failed and nor can I translate an appropriate error message.
What gives? How can I fetch a human-friendly error message and return it back as a JSON response?
Here's what I've got going so far... The biggest how-do-I is fetching the attribute name for the error message, but maybe there's a far easier way to manage this altogether...
/**
* Adds a new post to the system
*
* #param Request $request
* #return json
*/
public function store(Request $request)
{
// run validation
if(!empty($validator = $this->validate($request)))
{
return response()->json(trans('global/'.$validator->first(), ['attribute' => 'how to get attribute?!?!']), 400);
}
// some other logic...
}
/**
* Validates a post add or post update request
*
* #access private
* #param Request $request
* #return mixed
*/
private function validate(Request $request)
{
// set-up validation rules
$validator = Validator::make($request->all(), [
'username' => 'max:255|required',
'email' => 'email',
'service' => 'numeric|required',
]);
$validator->setAttributeNames([
'username' => "Username",
'service' => "Service",
]);
// run validation
if($validator->fails())
{
return $validator->errors();
}
return true;
}
Use code above in your controller store method and do not override validate method:
$rules = [
'username' => 'max:255|required',
'email' => 'email',
'service' => 'numeric|required',
];
$attributes = [
'username' => "Username",
'service' => "Service",
];
$this->validate($request, $rules, [], $attributes);
It will automatically returns errors json if validation fails.
Errors example:
{"username":["The Username field is required."],"service":["The Service field is required."]}

Categories