Customize a Json object to follow a specific format - php

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

How to convert Laravel 7 error json to this new json

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.

Insert into table is not working inside foreach Laravel 5.8

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

Laravel Custom Error Validation JSON Response Object to Array

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);

Customizing JSON response with additional index keys

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
);

Customizing The Flashed Error Format - Laravel 5.3

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"
]
}
}

Categories