How to validate params in REST Lumen/Laravel request? - laravel

Route:
$app->get('/ip/{ip}', GeoIpController::class . '#show');
How to validate ip's properly? I've tried to inject Request object in show method, but wasn't able to solve this. I want to stick with REST, so using URL parameters is not solution for me. I use it for API purposes, so status code as response would be appropriate.
Also tried that way:
$app->bind('ip', function ($ip) {
$this->validate($ip, [
'ip' => 'required|ip',
]);
});
EDIT:
The answer below is correct, I've found more info about requests in documentation:
Form requests are not supported by Lumen. If you would like to use form requests, you should use the full Laravel framework.
In other words, you cannot use custom requests via injection in constructors in Lumen.

The validate method takes the request object as the first parameter. Since you're passing the ip in the route, you need to create a custom validator.
public function show($ip)
{
$data = ['ip' => $ip];
$validator = \Validator::make($data, [
'ip' => 'required|ip'
]);
if ($validator->fails()) {
return $validator->errors();
}
return response()->json(['All good!']);
}
Edit : This is all laravel does under the hood. You could basically you this function directly to validate the ip and save a lot of effort.
protected function validateIp($ip)
{
return filter_var($ip, FILTER_VALIDATE_IP) !== false;
}

Related

Laravel HTTP Client dynamic call HTTP Method

I want to make all requests dynamic rather than defining Http in each function followed by httpMethod like this.
Http::post()
Http::put()
Http::delete()
what i tried.
function send($method, $url) {
Http::withToken($token)->{$method}($url)
}
function x() {
return $this->send('GET', 'url')
}
My code above works fine and i dont know if call a function from variable output like {$method} is best practice. but I want something similar like Guzzle.
(new Client)->request($method, $url, $options)
you need to accept that param like
function send($method,$url) {
retrun Http::withToken($token)->{$method}($url)
}
if you take a look at the source code here https://github.com/illuminate/http/blob/a28981924d318272053b87712740868d9b44899e/Client/PendingRequest.php laravel is using Guzzle. so basicly Http Client is Guzzle.
and every function like POST PUT etc call a function name send
so you can just direct call send function like this.
Http::withToken($token)
->send('POST', 'url', [
'headers' => [...]
'form_params' => [
...
]
])

What is the correct order of form validation and retrieving input values?

I wonder if I should do form validation before retrieving input values or vice versa.
I usually do validation first as I see no benefit in trying to access input values that might not be valid. However, a coworker looked at my code recently and found it strange. Is there any correct order for these steps?
public function createGroups(Request $request)
{
$this->validate($request, [
'courses' => 'required_without:sections',
'sections' => 'required_without:courses',
'group_set_name' => 'required',
'group_number' => 'required|integer|min:1'
]);
$courses = $request->input('courses');
$sections = $request->input('sections');
$group_set_name = $request->input('group_set_name');
$group_number = $request->input('group_number');
Positioning the validation for your controller logic at the beginning of a method is probably the way to go here, as you have required parameters defined. If you receive data that does not fully satisfy the requirements, you produce a validation error back to the user. This follows the productive "Fail Fast" line of thinking: https://en.wikipedia.org/wiki/Fail-fast
It's also important that you're not using any data that hasn't passed your stringent requirements from validation. Data that fails validation should no longer be trusted. Unless there's some other reason you need to be, say, logging any incoming data from the frontend, the order here looks good to me.
I totally agree with #1000Nettles response, to elaborate a little bit more on his/her answer (who should be the accepted one): There isn't any need to continue with your business logic when the data doens't comply with your specifications. Let's say you expected a string of a N characters long, because you defined your database with that limitation (in order to optimize the db desing), will you try to persist it even when it'll throw an exception? Not really.
Besides, Laravel has a particular way to extract validation classes: Form Request. This are injected in controllers. When a call reach the controller it means that already passed the validation, if not, an 422error be returned.
Create a custom request and keep the mess out of your controller, it doesn't even hit your controller function if validation failed and can just grab the data in your controller if validation passed.
php artisan make:request GroupRequest
In app/Http/Requests/GroupRequest.php:
public function authorize()
{
// return true;
return request()->user()-isAdmin; // <-- example, but true if anyone can use this form
}
public function rules()
{
return [
'courses' => ['required_without:sections'],
'sections' => ['required_without:courses'],
'group_set_name' => ['required'],
'group_number' => ['required', 'integer', 'min:1'],
];
}
The best part is you can even manipulate the data in here (GroupRequest.php) after it has been validated:
public function validated()
{
$validated = $this->getValidatorInstance()->validate();
// EXAMPLE: hash password here then just use new hashed password in controller
$validated['password'] = Hash::make($validated['password']);
return $validated;
}
In your controller:
public function createUser(UserRequest $request) // <- in your case 'GroupRequest'
{
$validated = $request->validated(); // <-- already passed validation
$new_user = User::create($validated); // <-- password already hashed in $validated
return view('dashboard.users.show')->with(compact('user'));
}
In your case, if you use my GroupRequest block above, you can return to view in 1 line of code:
public function createGroups(GroupRequest $request)
{
return view('example.groups.show')->with($request->validated()); // <-- already an array
}
In you blade view file, you can then use your variables like {{ $group_set_name }} and {{ $group_number }}

What are the benefits of using Laravel Request Class in API's development?

Is there any benefit of using laravel requests classes for store and update methods in developing restful API's? Or do I have to make custom Validator::make response?
I have been facing difficulty in modifying the response format from failed requests as to follow some development standards requirements.
Can we modify the failed responses format from request class for API's?
I prefer to use independent from request class because there is at least one benefit: more clear code.
you can generate response as you wish like this (this is my solution, maybe there are more better solutions. i use this solution to return only one validation error not all. you can modify it as you wish):
in your Form request class add this method:
protected function failedValidation(Validator $validator)
{
$this->validator = $validator;
foreach ($validator->messages()->getMessages() as $key => $value) {
$first_messages_only[$key] = $value[0];
}
throw new ValidationException($first_messages_only);
}
and then in your Exception handler class, write this block of code in your render() method:
if ($exception instanceof ValidationException) {
$response = [
'status' => false,
'message' => trans('api.general.validation_not_passed'), // $exception->getMessage()
'data' => ['validation_errors' => $exception->validator]
];
return response()->json($response);
}
Since you asked its usage in API development then you can easily tell request class that you want json response by adding application/json header in your request then it will return json response.
Request class is best approach to validate incoming input from user which provides a lot of other features as well.
In Request class you can write validation rules for all request types e.g. get,post,put|patch or delete
You can allow or disallow anyone using authorize method based on your project logic.
You can write custom messages and send them custom error message bags.
If you write whole thing in a controller method then that will not be a good approach and difficult to manage while request class will make you comfortable while dealing with validations only.
protected $errorBag = 'custom_errors_bag'
public function authorize()
{
return true; //or any other logic here to authorize the user
}
public function rules()
{
switch ($this->method()){
case 'POST':
return [
'username' => 'required|string|max:20|unique:users',
//...
];
case 'PUT':
case 'PATCH':
return [
'username' => 'required|string|max:20|unique:users,id',
//...
];
case 'DELETE':[
'id' => 'required'
//...
];
default:break;
}
}
public function messages()
{
return [
'username.required' => 'Please provide username',
'username.unique' => 'Username must be unique',
//...
];
}

Laravel - Change URL parameters using GET

I have RESTful API built on Laravel.
Now I'm passing parameter like
http://www.compute.com/api/GetAPI/1/1
but I want to pass parameter like
http://www.compute.com/api/GetAPI?id=1&page_no=1
Is there a way to change Laravel routes/functions to support this?
you can use link_to_route() and link_to_action() methods too.
(source)
link_to_route take three parameters (name, title and parameters). you can use it like following:
link_to_route('api.GetAPI', 'get api', [
'page_no' => $page_no,
'id' => $id
]);
If you want to use an action, link_to_action() is very similar but it uses action name instead of route.
link_to_action('ApiController#getApi', 'get api', [
'page_no' => $page_no,
'id' => $id
]);
href text
with these methods anything after the expected number of parameters is exceeded, the remaining arguments will be added as a query string.
Or you can use traditional concatination like following:
create a route in routes.php
Route::get('api/GetAPI', [
'as' => 'get_api', 'uses' => 'ApiController#getApi'
]);
while using it append query string like this. you can use route method to get url for required method in controller. I prefer action method.
$url = action('ApiController#getApi'). '?id=1&page_no=1';
and in your controller access these variables by following methods.
public function getApi(Request $request) {
if($request->has('page_no')){
$page = $request->input('page_no');
}
// ...your stuff
}
Or by Input Class
public function getApi() {
if(Input::get('page_no')){
$page = Input::get('page_no');
}
// ...your stuff
}
Yes you can use those parameters, then in your controllers you can get their values using the Request object.
public function index(Request $request) {
if($request->has('page_no')){
$page = $request->input('page_no');
}
// ...
}

laravel 5 double validation and request

I did this validation and works:
public function salvar(CreateEquipamento $Vequip, CreateLocalizacao $VLocal)
{
$this->equipamento->create($Vequip->all());
$equipamento = $this->equipamento->create($input);
return redirect()->route('equipamento.index');
}
what I want is to also do something like get the last created equipment ID and include in the array to validate and create for Local validation (CreateLocalizacao $VLocal) because i've two tables, one for the equipment and another one who stores all the places where my equipment was in.
$input['equipamento_id'] = $equipamento->id;
$this->localizacao->create($VLocal->all());
How could I do something like this?? thx in advance !
I do a "workarround" solution ;)
$localizacao = [
'equipamento_id' => $id,
'centrocusto_id' => $input['centrocusto_id'],
'projeto' => $input['projeto'],
'data_movimentacao' => $input['data_movimentacao']
];
$this->localizacao->create($VLocal->all($localizacao));
I dont know if this is the best way to do it but works, but if somebody has the right way to do post please!
Are you using Laravel 5?
If yes, use form Requests, they make everything easier. If you need to validate two things from one form, you just put two requests in the controller method. I use this when I register an user for an ecommerce page. I need to validate the user data and the address data, like this:
public function store(UserRegisterRequest $user_request, AddressCreateRequest $add_request)
{
//if this is being executed, the input passed the validation tests...
$user = User::create(
//... some user input...
));
Address::create(array_merge(
$add_request->all(),
['user_id' => $user->id]
));
}}
Create the request using artisan: php artisan make:request SomethingRequest, it generates an empty request (note the authorize function always returns false, change this to true or code that verifies that the user is authorized to make that request).
Here's an example of a Request:
class AddressCreateRequest extends Request {
public function authorize()
{
return true;
}
public function rules()
{
return [
"fullname" => "required",
//other rules
];
}
}
More on that on the docs:
http://laravel.com/docs/5.0/validation#form-request-validation

Resources