Laravel 5 - Remove Parameter From All Request Objects at Controller Level - laravel

I have URLs that look like:
http://example.com/api/user?id=45&name=mike&api_token=2348283
http://example.com/api/project?id=5&description=first&api_token=2348283
etc...
In my controllers, I have functions that look like:
public function user_get_endpoint(Request $request){
$request = $request->toArray();
return UserModel::where($request)->get()->toArray();
}
The above will currently break since the $request object contains a property called api_token which does not exist in the user table. I am using the api_token in a middleware to check for authentication.
I can manually unset the api_token property in each of my API functions by using unset($request['api_token'], but I'd like to avoid that if possible.
Is there anyway to do this application wide or at a class or controller level?

Laravel provides add and remove functions to add and remove new properties to the request object respectively.
$request->request->add(['api_token' => 'api_token']); // to add new property to $request
$request->request->remove('api_token'); // to remove property from $request

Perhaps you want global middleware?
First arrange for the middleware to run on all routes:
// routes.php
$app->middleware([
App\Http\Middleware\Apitoken::class
]);
Then define what the middleware should do:
// src/App/Http/Middleware/Apitoken.php
<?php
namespace App\Http\Middleware;
use Closure;
class Apitoken
{
public function handle($request, Closure $next)
{
unset($request['api_token']);
return $next($request);
}
}

Method 1
$request->except(['key1','key2',....])
provides an easy way to skip unwanted keys, similarly
Method 2
$request->only(['key3','key4',....])
provides an easy way to skip all others unwanted keys, I find both reasonably good for almost all scenarios

A solution that works for all HTTP Methods (not only for GET and HEAD) :
$except = ['api_token'];
$request = request();
$cleanup = $request->except($except);
$request->query = new \Symfony\Component\HttpFoundation\ParameterBag($cleanup);

Ideally, you should send your api_token in request headers instead of Uri params.
If you are using Laravel's auth:api Middleware for authentication then you can send api_token in headers as:
$response = $client->request('GET', '/api/user', [
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer '.$accessToken,
],
]);
Then api_token will never come in your Uri params.

As #JanWillem said in the comments you can use except() which will remove the params you pass to it:
public function user_get_endpoint(Request $request){
return UserModel::where($request->except('api_token'))->get();
}
https://laravel.com/docs/5.2/requests#retrieving-input and then scroll down to Retrieving A Portion Of The Input Data
Furthermore, you don't have to use toArray() with the response as Laravel will automatically do this for you.
Hope this helps!

Related

Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException The POST method is not supported for this route. Supported methods: GET, HEAD

these are my codes for route and controller
routes:
Route::get('/form/create','MyformController#create')->name('form');
Route::post('form', 'MyformController#store');
controller:
public function create()
{
return view('formsubmitted');
//i have put form.create as shown in a laravel tutorial
//but it was showing an error that view form.create is not found, hence i
//changed it to formsubmitted(i created that form)
}
public function store(Request $request)
{
$validateData = $request->validate(
[
'Full Name'=>'required',
'Email'=>'required',
'Feedback'=>'required',
]);
form::create($request->all());
}
I am new to laravel and doing the task of creating a feedback form and storing user info and answer to a database.
I hope to hear from you guys soon. Thank you
/form/create/ and form are two different routes. If you want the same route for the GET and POST function, the routes have to be the same.
Route::get('/form/create','MyformController#create')->name('form');
Route::post('/form/create', 'MyformController#store');
If it is rest api then it might me authentication issue
goto VerifyCsrfToken.php and add there your url for eception
for eg.
protected $except = [
'/anyotherurl',
'/api/userlist'
];

What's the best way to distinguish between multiple routes in Laravel using where constraints?

This does not work. The second route overwrites the first.
Route::get('user/{id}', function ($id) {
return 'This is User 1:' . $id;
})->where(['id' => '1']);
Route::get('user/{id}', function ($id) {
return 'This is User 2:' . $id;
})->where(['id' => '2']);
I could hardcode the value so 'user/1' works but then there is no $id variable on the request or accessible in the controller.
A more real world example would be
Route::put('purchase/{customerType}/{id}', 'InternalPurchaseController#submit')->where(['customerType' => 'internal']);
Route::put('purchase/{customerType}/{id}', 'ExternalPurchaseController#submit')->where(['customerType' => 'external']);
This is a simplified example of my needs, but basically I'd like $customerType to be accessible on the Request object. Currently I'm hardcoding the param in the route and using middleware to extract the values from the url, and manually setting them as params on the Request object. Is there a cleaner way to handle this?
If you like to call different controller according to route variable try this.
Route::put('purchase/{customerType}/{id}', function($customerType, $id){
if($customerType == internal){
return App::call('App\Http\Controllers\InternalPurchaseController#submit' . $id);
}
}

Laravel sub-domain routing set global para for route() helper

I have setup sub-domain routing on my app (using Laravel 5.4) with the following web.php route:
Route::domain('{company}.myapp.localhost')->group(function () {
// Locations
Route::resource('/locations' , 'LocationController');
// Services
Route::resource('/services' , 'ServiceController');
});
However as my show and edit endpoints require an ID to be passed, using a normal route('services.show') helper results in an ErrorException stating Missing required parameters for [Route: services.create] [URI: services/create].
I appreciate this is necessary, but as the company is associated to the user on login (and is in the sub-domain) I don't want to be passing this for every view. I want to set this at a global level.
To avoid repeated queries, I thought about storing this in the session as so (in the :
protected function authenticated(Request $request, $user)
{
$current_company = $user->companies->first();
$company = [
'id' => $current_company->id,
'name' => $current_company->name,
'display_name' => $current_company->display_name
];
$request->session()->put('company', $company);
}
Which is fine, but I wonder if I can pass this to the route as a middleware or something. What's be best solution here?
Recommendation: remove the slash before the resource name.
The resource method will produce the following URIs:
/services/{service}
So, you should define your routes like this:
Route::domain('{company}.myapp.localhost')->group(function () {
// Locations
Route::resource('locations' , 'LocationController');
// Services
Route::resource('services' , 'ServiceController', ['only' => ['index', 'store']]);
Route::get('services');
});
I ran into this exact issue today, I poked around in the source and found a defaults method on the url generator that allows you to set global default route parameters like so:
app('url')->defaults(['yourGlobalRouteParameter' => $value]);
This will merge in whatever value(s) you specify into the global default parameters for the route url generator to use.

How to validate params in REST Lumen/Laravel request?

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

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');
}
// ...
}

Resources