Laravel route duplication - laravel

I am working on building my first API. Currently, I have the following.
Route::group(['namespace' => 'Api', 'prefix' => 'api'], function () {
Route::get('/', 'AuthController#showLogin');
Route::post('login', 'AuthController#login');
Route::post('register', 'AuthController#register');
Route::group(['middleware' => ['jwt.auth']], function () {
Route::resource('account', 'AccountController');
Route::resource('notifications', 'NotificationController');
Route::resource('contacts', 'ContactController');
});
});
How can I make it that all requests to /api/v1 go to the API?
For future use, when I upgrade/add new features to an API going to /api, it's always the latest version. However, if a user goes to api/v1/, they use only version 1 of the API.

Related

How can I add one route to 2 different middleware (auth) without having to duplicate it in Laravel?

I know this is a basic laravel question but don't know how do it. How can I add one route to 2 different middleware (auth) without having to duplicate it?
// =admin
Route::group(['middleware' => ['auth']], function() {
Route::get('/dashboard', 'App\Http\Controllers\DashboardController#index')->name('dashboard');
Route::get('make-a-sale', [PurchasesController::class, 'index'])->name('make-a-sale.index');
});
// =cashier
Route::group(['middleware' => ['auth', 'role:cashier']], function() {
Route::get('/dashboard/cashier/profile', 'App\Http\Controllers\DashboardController#showCashierProfile')->name('dashboard.cashier.profile');
Route::get('make-a-sale', [PurchasesController::class, 'index'])->name('make-a-sale.index');
});
I have this route and I don't want to repeat calling this per auth middleware: Route::get('make-a-sale', [PurchasesController::class, 'index'])->name('make-a-sale.index');
You can't have two routes with the same url.
Route::get('make-a-sale', [PurchasesController::class, 'index'])->name('make-a-sale.index');
This route is inside both groups and since the url they will produce will be the same, only the second will remain.
Route::group(['middleware' => ['auth']], function() {
Route::get('/dashboard', 'App\Http\Controllers\DashboardController#index')->name('dashboard');
//Route::get('make-a-sale', [PurchasesController::class, 'index'])->name('make-a-sale.index');
// this route will be ignored because the other one has the same url
});
Route::group(['middleware' => ['auth', 'role:cashier']], function() {
Route::get('/dashboard/cashier/profile', 'App\Http\Controllers\DashboardController#showCashierProfile')->name('dashboard.cashier.profile');
Route::get('make-a-sale', [PurchasesController::class, 'index'])->name('make-a-sale.index');
});
If you want Laravel to handle these two routes differently, you have to add a prefix:
Route::group(['prefix' => 'admin', 'as' => 'admin.', 'middleware' => ['auth']], function() {
Route::get('/dashboard', 'App\Http\Controllers\DashboardController#index')->name('dashboard');
//Route::get('make-a-sale', [PurchasesController::class, 'index'])->name('make-a-sale.index');
// this route will be ignored because the other one has the same url
});
Route::group(['prefix' => 'cashier', 'as' => 'cashier.', 'middleware' => ['auth', 'role:cashier']], function() {
Route::get('/dashboard/cashier/profile', 'App\Http\Controllers\DashboardController#showCashierProfile')->name('dashboard.cashier.profile');
Route::get('make-a-sale', [PurchasesController::class, 'index'])->name('make-a-sale.index');
});
This way, when the url will be prefixed with admin, the first route will be called (without the role:cashier middleware).
Notice that I added a route name prefix ('as' => 'admin.' / 'as' => 'cashier.') so you can call each one by name, using:
route('admin.make-a-sale.index'); // admin/make-a-sale
//or
route('cashier.make-a-sale.index'); // cashier/make-a-sale
Just to add, if someone wants to fix the Laravel blade error below whenever you clear your browser cache and was automatically logout:
*Attempt to read property "name" ...*
You need to add all your routes inside the:
Route::group(['middleware' => ['auth']], function () {
// routes here
});
This will redirect you to login once that happens.

Is there a different way I should be naming my Laravel routes?

I currently have these routes in my API:
Route::group(['prefix' => 'v1'], function() {
Route::get('feed', [FeedController::class, 'index']);
Route::get('feed/{page}', [FeedController::class, 'index']);
});
I wanted to create another route that looked like this, only protected by some middleware:
Route::group(['prefix' => 'v1', 'middleware' => ['jwt.verify']], function() {
Route::get('feed/following', [FeedController::class, 'following']);
Route::get('feed/following/{page}', [FeedController::class, 'following']);
});
However, it appears that the v1/feed/following route is actually being routed to the v1/feed/{page} route.
Is there a way to fix this without my route names?
You can introduce another group in your v1 Api path and set feed/following before feed/{page}:
Route::group(['prefix' => 'v1'], function() {
Route::group(function() {
Route::get('feed/following', [FeedController::class, 'following']);
Route::get('feed/following/{page}', [FeedController::class, 'following']);
})->middleware('jwt.verify');
Route::get('feed', [FeedController::class, 'index']);
Route::get('feed/{page}', [FeedController::class, 'show']);
});
The rule for 'feed/{page}' will also match 'feed/following', you will wind up with page = following
Maybe create the route for 'feed/following' before the route for 'feed/{page}'

Is there another, more efficient way to nest prefix and name prefix in laravel 8 that doesn't need to use so many groups?

I saw a good way to nest prefix and name prefix, but this is so verbose. In addition, for few requests, it's acceptable, but when there is a lot of requests, creating groups can be problematic. This is a toy example.
Route::prefix('auth')->group(function () {
Route::name('auth.')->group(function () {
Route::get('login', [MainController::class, 'login'])->name('login');
Route::get('register', [MainController::class, 'register'])->name('register');
});
});
I try this, but it failed.
Route::name('auth.')->group(['prefix'=>'auth'], function () {
Route::get('login', [MainController::class, 'login'])->name('login');
Route::get('register', [MainController::class, 'register'])->name('register');
});
Is there another, more efficient way to nest prefix and name prefix in laravel 8 that doesn't need to use so many groups?
I'm using the Laravel 8 Documentation's route group section.
You can combine your prefixes, names and middlewares in the group function which will tidy things up somewhat:
Route::group(['prefix' => 'auth', 'as' => 'auth.'], function () {
Route::get('login', [MainController::class, 'login'])->name('login');
Route::get('register', [MainController::class, 'register'])->name('register')
});
If you want to specify middleware on the group, just add it to the array in the first argument for the group function.
Route::group(['prefix' => 'auth', 'as' => 'auth.', 'middleware' => [...]], function () {
...
});

Laravel 5.2 redirect doesn't save flash messages

I installed fresh laravel 5.2.29.
My routes.php:
Route::group(['middleware' => ['web']], function () {
Route::get('/a', function () {
return redirect('/b', 302)->with('error', 'error description');
});
Route::get('/b', function () {
return session('error');
});
});
When I go to /a in browser it redirects me to /b, but shows me nothing. What should I do to it show me error description? Or why does not it store flash data?
Basically, if you are running Laravel 5.2.27 and up, do not use the web middleware group. It is applied for you by default as you can see in app/Http/RouteServiceProvider.php:
protected function mapWebRoutes(Router $router)
{
$router->group([
'namespace' => $this->namespace, 'middleware' => 'web',
], function ($router) {
require app_path('Http/routes.php');
});
}
If you try to apply the web middleware again, you'll run into weird problems like what you are currently facing.

Multi domain routing in Laravel 5.2

I have setup multi-domain routing in my laravel 5.2 app. What I want to achieve is if a user hits, membership.app, he should be served different homepage as compared to user who hits, erp.app domain.
Route::pattern('erp', 'erp.app|erp.domain.com');
Route::pattern('membership', 'membership.app|membership.domain.com');
Route::group(['middleware' => ['web', 'auth'], 'domain' => '{erp}'], function() {
Route::get('/', 'HomeController#getIndex');
Route::controller('members', 'MembersController');
Route::controller('users', 'UsersController');
Route::controller('settings', 'SettingsController');
});
Route::group(['middleware' => 'web', 'domain' => '{erp}'], function () {
Route::controller('auth', 'Auth\AuthController');
});
Route::group(['middleware' => 'web', 'domain' => '{membership}'], function () {
Route::controller('/', 'BecomeMemberController');
});
Route::group(['middleware' => 'web'], function () {
Route::controller('ajax', 'AjaxController');
});
I tried this setup, but it breaks the code with first param in each controller method being the url instead of intended value.
Suppose I have a method hello in members controller.
public function hello($param1, $param2)
{
....
}
If I access erp.app/members/hello/1/2 url and try to print out $param1 of controller method, it returns erp.app instead of intended 1 in this case.
Please help.
I don't know why aren't you seperating the routes to different controllers as you say the output will be quite different...
A quick example of to use that:
Route::group(['domain' => '{type}.myapp.com'], function () {
Route::get('members/hello/{id1}/{id2}', function ($type, $id1, $id2) {
// when you enter --> members.myapp.com/hello/12/45
var_dump($type); //memebers
var_dump($id1); //12
var_dump($id2); //45
});
});

Resources