Keep Your Laravel Routes Clean on Any Project Size

Keep Your Laravel Routes Clean on Any Project Size

ยท

4 min read

In this post, I'm going to show you how you can organize routes in various size projects. From small projects to large, I'll show you some techniques that have kept a growing monolith's routes in a manageable state.

Route prefixing

The feature I rely on most when organizing routes is route prefixing. Route::group() is an incredibly powerful method for organizing routes. Let's use the example /admin.

Without prefixing

Route::get('/admin', '\App\Http\Controllers\AdminController@index');
Route::get('/admin/profile', '\App\Http\Controllers\AdminController@profile');
Route::get('/admin/payments', '\App\Http\Controllers\AdminController@payments');
Route::group(['prefix' => '/admin'], function () {
  Route::get('/', '\App\Http\Controllers\AdminController@index');
  Route::get('/profile', '\App\Http\Controllers\AdminController@profile');
  Route::get('/payments', '\App\Http\Controllers\AdminController@payments');
});

Already, we're able to organize our routes by domain & responsibility. This also allows us to nest these groups for even tighter grouping & control:

Route::group(['prefix' => '/admin'], function () {  
    Route::get('/', '\App\Http\Controllers\AdminController@index');
    Route::group(['prefix' => '/payments'], function() {
        Route::get('/', '\App\Http\Controllers\AdminController@payments');
        Route::get('/{payment}', '\App\Http\Controllers\AdminController@showPayment');
        Route::delete('/{payment}', '\App\Http\Controllers\AdminController@deletePayment');
    });
});

Middleware

The Route::group() method is also great for declaring middleware for an entire group. Let's use our last example. We can add the auth middleware to the entire group like this:

Route::group( ['prefix' => '/admin', 'middleware' => ['auth'] ], function () {
  // routes here
});

Naming


๐Ÿ’ก TL;DR Why Naming Rocks

Naming your routes can provide many benefits while writing your application. Just a quick tl;dr on why named routes are so important:

Let's say in our profile.blade.php, we've got a link to logout like so:

<a href="/logout">Logout</a>

And our route is declared as

Route::get('/logout', 'AuthController@logout');

This is fine, but if we change our route to

Route::get('/auth/logout', 'AuthController@logout');

Suddenly, all the locations we hard coded that path will 404!

If we rely on naming instead, we can write our blade templates to use names using the route() helper. The actual path will update automatically.

<a href="{!! route('logout'); !!}">Logout</a>

This will always work (provided we keep the same name) despite what we do with the path declared in the controller.


Back to our example, let's use naming to organize our routes:

Route::group( ['prefix' => '/admin', 'as' => 'admin.' ], function () {
  Route::get('/', 'AdminController@index')->name('index');
});

All routes in this group will inherit the admin. prefix. So the route declared in this example will be admin.index. This is a great way to keep your route naming organized by domain.

Custom Route Files

On larger projects, it can be helpful to break up the routes file into separate files to separate responsibilities. In our example above, let's say our /admin domain has really grown. It's probably time to create our own /routes/admin.php.

We start by creating a file, /routes/admin.php. Next we create a method on the RouteServiceProvider.php class:

    protected function mapAdminRoutes()
    {
        Route::prefix('admin')
        ->middleware(['web', 'auth'])
        ->as('admin.')
        ->group(base_path('routes/admin.php'));
    }

Then, all we do is register it by calling this method in the map() method on the RouteServiceProvider.

    public function map()
    {
        // ... 
        $this->mapAdminRoutes();
    }

Get routing!

Tl;dr my main methods for organizing routes for Laravel apps of various sizes: