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);
}
Related
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.
I amtrying to insert values to laravel table inside a foreach. In my view I am selecting some checkboxes and I need its value to get inserted into a table. In my controller, I am getting all the required values to be inserted into the table. But everytime when I run, the code inside the foreach results in error.
Here is my controller code.
try {
$e_id = request()->segment(3);
$et = $repository->find($e_id);
if (!empty($et)) {
$rules = [
's_users' => 'bail|required|array',
'e_id' => 'bail|required',
];
$messages = [
's_users.required' => required,
'e_id.required' => required ,
's_users.array' => required,
];
$validator = Validator::make($request->all(), $rules, $messages);
if ($validator->fails()) {
return response()->json(['error' => 1, 'code' => 422, 'errors' => $validator->errors()], 422);
} else {
DB::transaction(function () use ($request, $admin) {
DB::table('e_users')->whereIn('user_id', $request->input('s_users'))->delete();
foreach ($request->input('s_users') as $suser) {
$eUsers = new EUsers();
$eUsers->e_id = $request->input('e_id');
$eUsers->uid = $suser;
$eUsers->save();
}
});
return response()->json(['error' => 0, 'code' => 200, 'message' => "success"], 200);
}
} else {
throw new \Exception("invalid);
}
} catch (\Exception $e) {
return response()->json(['error' => 1, 'code' => 200, 'message' => "unknown error occurred"], 200);
}
The above code always throws exception, which shows unknown error occured. Thanks in advance
I try to create an API for the registration form if a user does not fill the required field. The validator show error in object format but i need json response in an array format.
$validator = Validator::make($request->all(), [
'name' => 'required',
'mobile' => 'required',
'address' => 'required',
]);
if ($validator->fails()) {
return response()->json(['error'=>$validator->errors()], 401);
}
Current output is
{
"error": {
"name": [
"The name field is required."
],
"mobile": [
"The mobile field is required."
],
"address": [
"The addressfield is required."
]
}
}
Expected output
{
"error": [
"The name field is required.",
"The mobile field is required.",
"The address field is required."
]
}
Correct answer is this one:
$err = array();
foreach ($validator->errors()->toArray() as $error) {
foreach($error as $sub_error){
array_push($err, $sub_error);
}
}
return ['errors'=>$err];
the inner foreach is added because maybe more than one validation condition fails for an input( like : password is too short & too weak).
and Mayank Pandeyz's answer for loop won't iterate because until we add toArray() to the end of $validator->errors().
For getting the expected result, iterate the $validator->errors() using foreach() loop and push all the values in an array and return that array like:
$err = array();
foreach ($validator->errors() as $error)
{
array_push($err, $error);
}
return response()->json(['error'=>$err], 401);
I use the response() helper on HTTP Response as documented. The straightforward use:
response()->json(
$this->response,
$this->status
)->withHeaders([]);
This will output:
{
"key" : "desired response"
}
However, I wanted to add a key on the response:
$return['message'] = 'Request successful';
$return['data'] = response()->json(
$this->response,
$this->status
)->withHeaders([]);
But the response resulted to:
{
"message": "Request successful",
"data": {
"headers": {},
"original": {
"key" : "desired response"
},
"exception": null
}
}
There are extra keys on the response: headers, original & exception. How can I get rid of that in order to achieve this desired format:
{
"message": "Request successful",
"data": {
"key" : "desired response"
}
}
You can you Laravel Provider
php artisan make:provider ResponseMacroServiceProvider
<?php
namespace App\Providers;
use Response;
use Illuminate\Support\ServiceProvider;
class ResponseMacroServiceProvider extends ServiceProvider
{
/**
* Bootrap the application service
*/
public function boot() {
Response::macro('success', function ($headers, $originals) {
return Response::json([
'message' => "Request successful",
'data' => [
'headers' => $headers,
'original' => $originals,
],
'error' => [
'code' => 0 ,
'message' => []
]
]);
});
Response::macro('error', function ($message, $status = 400) {
if(is_array($message))
$message_repsonse = $message;
else
$message_repsonse = [$message];
return Response::json([
'message' => "Request failed",
'data' => [
'headers' => null,
'original' => null,
]
'error' => [
'code' => $status,
'message' => $message_repsonse
]
]);
});
}
/**
* Register application service
* #override
*/
public function register() {
}
}
Edit your config/app.php
/*
* Application Service Providers...
*/
App\Providers\ResponseMacroServiceProvider::class,
And try to handle at your Controller
$headers = 'Your header';
$originals = Your_Model::find(1);
return response()->success($headers, $originals);
return response()->error($validator->errors()->all(), 300);
you can achieve this by using this code:
$return =[] ;
$return['message'] = 'Request successful'; // your message
$return['data'] = $this->response; // your data
return response()->json( // return json
$return, // your data here
$this->status // status here
);
I want to customize the format of flashed error message, that is recieved after i do something like $this->validator($request->all())->validate();
For an ajax request, it responds with:
{
"name": [
"The name field is required."
],
"email": [
"The email field is required."
],
}
But i want it to look like
{
"status": "fail",
"errors": {
"name": [
"The name field is required."
],
"email": [
"The email field is required."
],
}
}
I read the documentation under Customizing The Flashed Error Format and added formatValidationErrors method in my Controller class, but it's not making any difference.
public function formatValidationErrors(Validator $validator)
{
return ['status' => 'fail', 'errors' => $validator->errors()->getMessages()];
}
It's not changing even if i change formatValidationErrors method in the original Illuminate\Foundation\Validation\ValidatesRequests trait
I'm forced have to build this format in all request calls and so there's code-duplication. It would be nice if i could just call $this->validator($request->all())->validate() and it automatically formats as per my requirement.
The way to change it is to create a class that extends Validator and override the addError method. Here's a sample code:
<?php
namespace App\Validators;
use Illuminate\Support\MessageBag;
use Illuminate\Validation\Validator;
class RestValidator extends Validator {
/**
* Add an error message to the validator's collection of messages.
*
* #param string $attribute
* #param string $rule
* #param array $parameters
* #return void
*/
protected function addError($attribute, $rule, $parameters)
{
$message = $this->getMessage($attribute, $rule);
$message = $this->doReplacements($message, $attribute, $rule, $parameters);
$customMessage = new MessageBag();
$customMessage->merge(['code' => strtolower($rule.'_rule_error')]);
$customMessage->merge(['message' => $message]);
$this->messages->add($attribute, $customMessage);
}
}
Now you can structure the validation in your controllers like so:
$rules = [
// Your rules here
];
$attributes = [
// The attributes you're checking here
];
$validator = Validator::make($attributes, $rules);
if ($validator->fails()) {
$errorMessage = [
'status' => 'fail',
'errors' => $validator->errors()
];
return $errorMessage;
}
// The rest of your code goes here
Try this in your model,
public function response(array $errors)
{
if (($this->ajax() && !$this->pjax()) || $this->wantsJson()) {
$errors = array('status' => 'fail', 'errors' => $errors);
return new JsonResponse($errors, 422);
}
return $this->redirector->to($this->getRedirectUrl())
->withInput($this->except($this->dontFlash))
->withErrors($errors, $this->errorBag);
}
It will result as you expected,
{
"status": "fail",
"error": {
"name": [
"The name field is required."
],
"email": [
"The email field is required"
]
}
}