Laravel : Validation not working when testing on live - laravel

Create a user validate function with validation in API integration When i try to validate user with some validation and check it in postman it is working perfect in local machine but when i uploaded code on server and test, it is not working.
Controller function :
public function confirmUser(ForgotPasswordRequest $request)
{
// ForgotPasswordRequest for validate
$user = User::leftjoin('user_details','users.id', '=', 'user_details.user_id')
->where('user_details.phone', '=', $request->post('phone'))
->where('users.email', '=', $request->post('email'))
->first();
if(!$user) {
return response()->json([
'message' => "The credentials you provided cannot be determined to be authentic.!!",
'status_code' => 404,
]);
}
$token = JWTAuth::fromUser($user);
return response()->json([
'message' => "Your account is eligible for change password.!!",
'token' => $token,
'status_code' => 200
]);
}
My forgotPasswordRequest.php code :
<?php
namespace App\Api\V1\Requests;
use Config;
use Dingo\Api\Http\FormRequest;
class ForgotPasswordRequest extends FormRequest
{
public function rules()
{
return Config::get('boilerplate.forgot_password.validation_rules');
}
public function authorize()
{
return true;
}
}
And in config folder boilerplate.php file contain forgot_password rules :
'forgot_password' => [
'validation_rules' => [
'email' => 'required|email',
'phone' => 'required|min:11|numeric'
]
],
When email and phone null it returns only email validation not phone:
{
"error": {
"message": "422 Unprocessable Entity",
"errors": {
"email": [
"The email field is required."
]
},
"status_code": 422
}
}
What i am doing wrong ? It is related to cookies ?

There is nothing going wrong here.
Laravel checks whether the email field is properly filled in. It isn't, Laravel breaks out of the validation method and returns the exception.
If you fill in the email field, but leave the phone field blank, then the validation response will be about the phone field.

Related

How to remove console error 422 (Unprocessable Content)

I write validation for email in my controller
public function store(Request $request)
{
/*
* validate request
*/
$request->validate([
'email' => ['required', 'unique:leads', 'email'],
]);
return response()->json([],422);
if (\App\Models\Lead::where(['email' => $request->get('email')])->count() > 0) {
// user found
return response()->json([ 'data' => [
'message' => 'lindirizzo email è già registrato'
]], 200);
}
else {
// Register the new user or whatever.
$client = \App\Models\Lead::create(['email' => $request->get('email'),]);
return response()->json([ 'data' => [
'message' => 'Registrato con successo!'
]], 201);
}
}
And when i write the same email in front i get error POST http://127.0.0.1:8000/api/register/leads 422 (Unprocessable Content)
My network respons its ok,
{"message":"validation.unique","errors":{"email":["validation.unique"]}}
But i dont want to show error in console
This line of code is unnecessary.
// ...
return response()->json([],422);
// ...
Remove it.
Writing The Validation Logic
... if the validation fails, the proper response will automatically be
generated. If the validation passes, our controller will continue
executing normally.
Addendum
The block of code below is unnecessary as well since the validation rule 'unique:leads' is sufficient:
// ...
if (\App\Models\Lead::where(['email' => $request->get('email')])->count() > 0) {
// user found
return response()->json([ 'data' => [
'message' => 'lindirizzo email è già registrato'
]], 200);
}
// ...
Remove it as well!
If you wish to have a custom message for the "unique email" validation, add it as the second parameter of the ->validate(...) method:
$request->validate([
'email' => ['required', 'unique:leads', 'email'],
], [
'email.unique' => 'lindirizzo email è già registrato'
]);
First, you need to check is there any email is available already or not in the table.
If you found any count of that email then simply ignore creating a record else you can add that email with a new entry inside the database.
if (Lead::where(['email' => $request->get('email')])->count() > 0) {
return response()->json([ 'data' => [
'message' => 'User data get successfully'
]], 200);
}else{
// Add a user with new email and send json response
}
}

Find data before validate form request laravel

I want to update the data using the request form validation with a unique email role, everything works normally.
Assume I have 3 data from id 1-3 with url:
127.0.0.1:8000/api/user/update/3
Controller:
use App\Http\Requests\Simak\User\Update;
...
public function update(Update $request, $id)
{
try {
// UPDATE DATA
return resp(200, trans('general.message.200'), true);
} catch (\Exception $e) {
// Ambil error
return $e;
}
}
FormRequest "Update":
public function rules()
{
return [
'user_akses_id' => 'required|numeric',
'nama' => 'required|max:50',
'email' => 'required|email|unique:users,email,' . $this->id,
'password' => 'required',
'foto' => 'nullable|image|max:1024|mimes:jpg,png,jpeg',
'ip' => 'nullable|ip',
'status' => 'required|boolean'
];
}
but if the updated id is not found eg:
127.0.0.1:8000/api/user/update/4
The response gets The email has already been taken.
What is the solution so that the return of the data is not found instead of validation first?
The code looks like it should work fine, sharing a few things below that may help.
Solution 1: Check if $this->id contains the id you are updating for.
Solution 2: Try using the following changes, try to get the id from the URL segment.
public function rules()
{
return [
'user_akses_id' => 'required|numeric',
'nama' => 'required|max:50',
'email' => 'required|email|unique:users,email,' . $this->segment(4),
'password' => 'required',
'foto' => 'nullable|image|max:1024|mimes:jpg,png,jpeg',
'ip' => 'nullable|ip',
'status' => 'required|boolean'
];
}
Sharing one more thing that may help you.
Some person uses Request keyword at the end of the request name. The Update sounds generic and the same as the method name you are using the request for. You can use UpdateRequest for more code readability.
What I understand from your question is, you need a way to check if the record really exists or not in the form request. If that's the case create a custom rule that will check if the record exists or not and use that rule inside your request.
CheckRecordRule
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class CheckRecordRule implements Rule
{
protected $recordId;
public function __construct($id)
{
$this->recordId = $id;
}
public function passes($attribute, $value)
{
// this will check and return true/false
return User::where('id', $this->recordId)->exists();
}
public function message()
{
return 'Record not found.';
}
}
Update form request
public function rules()
{
return [
'email' => 'required|email|unique:users,email,' . $this->id.'|'. new CheckRecordRule($this->id),
];
}
So when checking for duplicate it will also check if the record really exists or not and then redirect back with the proper message.

Laravel Test on controller returning uncorrect status code

I'm trying to create a test on a rest API using Laravel. My test is in 3 steps : Arrange, act and assert.
During the first step I create an entry in the database. For the second test i query my DB, finally i check if the tests are true or not.
use RefreshDatabase;
/** #test */
public function createTest() {
// Arrange : name & message OK
$message = ChatMessages::create([
'username' => 'My name is long enough',
'message' => 'my message is also OK'
]);
// Act
$getAllMessages = ChatMessages::all();
$this->post('/message', $message->toArray())
->assertStatus(200)
->assertExactJson([
'status' => 'ok', 'chat_message' => $message->toArray()
]);
// assert : if name too short, data is not persisted
$this->assertEquals(sizeof($getAllMessages), 1);
}
My route :
Route::post('/message', 'ChatController#create');
I have the following error message :
Expected status code 200 but received 404.
Failed asserting that false is true.
In my Controller I have this code :
public function create(Request $request) {
$input = $request->validate([
'username' => 'required|string|min:3|max:255',
'message' => 'required|string|min:1',
]);
try {
$message = ChatMessages::create([
'username' => $input['username'],
'message' => $input['message'],
]);
} catch (\Exception $err) {
Log::error("Cannot fetch chat messages");
Log::error($err);
abort(500);
}
return response()->json(['status' => 'ok', 'chat_message' => $message]);
}
$request->validate should give a 302 redirection if not satisfied and 200 if OK.

change the format of laravel API Errors and Exceptions

I write api for the applications with laravel.
for example I have two field which are "city_id" and "address" and I validate them with these rules :
$request->validate([
'city_id' => 'bail|required|numeric',
'address' => 'required'
]);
if validation fails the response will be :
{
"message": "The given data was invalid.",
"errors": {
"city_id": ["The city id field is required."]
}
}
everything is fine but I want change the validation error at api response to this :
{
"msg" => 'The city id field is required.'
}
actually I want send one error without the key . where can I change that?
You can write/modify the Laravel exceptions handler. Here you can read more about it here https://laravel.com/docs/5.8/errors or here https://laravel.com/docs/6.x/errors (depends what version of Laravel you using)
Example:
class Handler extends ExceptionHandler
{
...
public function render($request, Exception $e)
{
if ($exception instanceof ValidationException) {
return new JsonResponse(
['msg' => $e->getMessage()],
400
);
}
}
...
}

Better way for testing validation errors

I'm testing a form where user must introduce some text between let's say 100 and 500 characters.
I use to emulate the user input:
$this->actingAs($user)
->visit('myweb/create')
->type($this->faker->text(1000),'description')
->press('Save')
->see('greater than');
Here I'm looking for the greater than piece of text in the response... It depends on the translation specified for that validation error.
How could do the same test without having to depend on the text of the validation error and do it depending only on the error itself?
Controller:
public function store(Request $request)
{
$success = doStuff($request);
if ($success){
Flash::success('Created');
} else {
Flash::error('Fail');
}
return Redirect::back():
}
dd(Session::all()):
`array:3 [
"_token" => "ONoTlU2w7Ii2Npbr27dH5WSXolw6qpQncavQn72e"
"_sf2_meta" => array:3 [
"u" => 1453141086
"c" => 1453141086
"l" => "0"
]
"flash" => array:2 [
"old" => []
"new" => []
]
]
you can do it like so -
$this->assertSessionHas('flash_notification.level', 'danger'); if you are looking for a particular error or success key.
or use
$this->assertSessionHasErrors();
I think there is more clear way to get an exact error message from session.
/** #var ViewErrorBag $errors */
$errors = request()->session()->get('errors');
/** #var array $messages */
$messages = $errors->getBag('default')->getMessages();
$emailErrorMessage = array_shift($messages['email']);
$this->assertEquals('Already in use', $emailErrorMessage);
Pre-requirements: code was tested on Laravel Framework 5.5.14
get the MessageBag object from from session erros and get all the validation error names using $errors->get('name')
$errors = session('errors');
$this->assertSessionHasErrors();
$this->assertEquals($errors->get('name')[0],"The title field is required.");
This works for Laravel 5 +
Your test doesn't have a post call. Here is an example using Jeffery Way's flash package
Controller:
public function store(Request $request, Post $post)
{
$post->fill($request->all());
$post->user_id = $request->user()->id;
$created = false;
try {
$created = $post->save();
} catch (ValidationException $e) {
flash()->error($e->getErrors()->all());
}
if ($created) {
flash()->success('New post has been created.');
}
return back();
}
Test:
public function testStoreSuccess()
{
$data = [
'title' => 'A dog is fit',
'status' => 'active',
'excerpt' => 'Farm dog',
'content' => 'blah blah blah',
];
$this->call('POST', 'post', $data);
$this->assertTrue(Post::where($data)->exists());
$this->assertResponseStatus(302);
$this->assertSessionHas('flash_notification.level', 'success');
$this->assertSessionHas('flash_notification.message', 'New post has been created.');
}
try to split your tests into units, say if you testing a controller function
you may catch valication exception, like so:
} catch (ValidationException $ex) {
if it was generated manually, this is how it should be generated:
throw ValidationException::withMessages([
'abc' => ['my message'],
])->status(400);
you can assert it liks so
$this->assertSame('my message', $ex->errors()['abc'][0]);
if you cannot catch it, but prefer testing routs like so:
$response = $this->json('POST', route('user-post'), [
'name' => $faker->name,
'email' => $faker->email,
]);
then you use $response to assert that the validation has happened, like so
$this->assertSame($response->errors->{'name'}[0], 'The name field is required.');
PS
in the example I used
$faker = \Faker\Factory::create();
ValidationException is used liks this
use Illuminate\Validation\ValidationException;
just remind you that you don't have to generate exceptions manually, use validate method for common cases:
$request->validate(['name' => [
'required',
],
]);
my current laravel version is 5.7

Resources