How to separate your Routes at Laravel conveniently.
mohammed osama
Posted on March 25, 2020
I think we all have encountered a situation where we had a massive file contains our routes. I can't lie, this was driving me crazy for a long time and I had to figure a solution to tackle this issue. So, Here is what I have ended up using to structure my routes files.
Initially, I thought of making use of the fact that the group route method accepts a file, and that's how laravel addresses our routes at RouteServiceProvider
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
/**
* This namespace is applied to your controller routes.
*
* In addition, it is set as the URL generator's root namespace.
*
* @var string
*/
protected $namespace = 'App\Http\Controllers';
/**
* Define your route model bindings, pattern filters, etc.
*
* @return void
*/
public function boot()
{
//
parent::boot();
}
/**
* Define the routes for the application.
*
* @return void
*/
public function map()
{
$this->mapApiRoutes();
$this->mapWebRoutes();
//
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* @return void
*/
protected function mapWebRoutes()
{
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*
* @return void
*/
protected function mapApiRoutes()
{
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
}
}
I abstracted the routes which concern the user for example to a file called users.php and duplicated the mapApiRoutes to be mapUsersRoutes and navigated to my users.php file.
/**
* Define the routes for the application.
*
* @return void
*/
public function map()
{
$this->mapApiRoutes();
$this->mapWebRoutes();
$this->mapUsersRoutes();
//
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*
* @return void
*/
protected function mapUsersRoutes()
{
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/users.php'));
}
I know what you are thinking of, apparently, this isn't the best solution as whenever we start to create a new file, we will have to register it as we did before. So, I had to improve this initial idea.
I thought of breaking the routes file into regions that are common across the whole application, and I've come into a thought that all of our routes can't be out of this scope: authenticated, guest, and public routes.
I structured my routes folder to the following:
├── routes
│ ├── api
│ │ ├── public
│ | │ ├── users.php
│ │ ├── auth
│ | │ ├── users.php
│ │ ├── guest
│ | │ ├── users.php
at first glance, you might think that "well, It didn't change much, we are going to map these files again". But, we can actually make use of a function called "glob" that php provides by nature which is sort of out of the box solution, as we aren't coupled to laravel solutions.
glob accepts a pattern and can find filenames under a path that's matching our pattern. Hence our routes are structured under specific folders, we can now find all of the files under these folders and register them to their middlewares.
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
/**
* This namespace is applied to your controller routes.
*
* In addition, it is set as the URL generator's root namespace.
*
* @var string
*/
protected $namespace = 'App\Http\Controllers';
/**
* Define the routes for the application.
*
* @return void
*/
public function map()
{
$this->mapAuthRoutes();
$this->mapGuestRoutes();
$this->mapPublicRoutes();
// $this->mapWebRoutes();
//
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* @return void
*/
protected function mapWebRoutes()
{
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*
* @return void
*/
protected function mapAuthRoutes()
{
foreach (glob(base_path('routes/api/auth/*.php')) as $file) {
Route::prefix('api')
->middleware(['api', 'auth:api'])
->group($file);
}
}
protected function mapGuestRoutes()
{
foreach (glob(base_path('routes/api/guest/*.php')) as $file) {
Route::prefix('api')
->middleware(['api', 'guest:api'])
->group($file);
}
}
protected function mapPublicRoutes()
{
foreach (glob(base_path('routes/api/public/*.php')) as $file) {
Route::prefix('api')
->middleware('api')
->group($file);
}
}
}
Now, whenever we create a new file, the foreach is going to have it as it's a matching pattern (the file is under the pathname and it has the extension of PHP, so it matches our pattern). Brilliant!, but hold on for a minute.
How these files are going to be registered?
If you reviewed laravel's lifecycle, you would understand that service providers are part of the lifecycle of laravel's request, which we can make use of this feature to register our routes dynamically.
That's it for this one!, I hope you enjoyed it. Don't forget to follow me! ✌️
Posted on March 25, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 28, 2024