Laravel Route Tips to Improve Your Routing

Tutorials

April 2nd, 2018

laravel-route-tips.png

The Laravel router has a great, well-polished API when you first dive into Laravel as a beginner or newcomer to the framework. What follows is not anything hidden or new, but a few tips that should help you when you’re learning Laravel 5.

The documentation is excellent, and the tips that follow supplement and piece together a few parts that will help you get a quick jumpstart on learning how to use routing in your Laravel applications.

Custom Namespaces

As outlined in the documentation, if you want a group of routes to use a namespace like App\Http\Controllers\Admin, you can define a namespace using the fluent routing API introduced in Laravel 5.4:

1Route::namespace('Admin')->group(function () {
2 // Controllers Within The "App\Http\Controllers\Admin" Namespace
3});

This is exactly the technique used in the RouteServiceProvider found in each Laravel project:

1protected function mapWebRoutes()
2{
3 Route::middleware('web')
4 ->namespace($this->namespace)
5 ->group(base_path('routes/web.php'));
6}

Because the routes/web.php file has a namespace, our Admin namespace relatively.

To create controllers in the App\Http\Controllers\Admin, you can run the following console command:

1php artisan make:controller -r Admin/UsersController

Within our previous routing example, our definition might look like this in the routes/web.php file:

1Route::namespace('Admin')
2 ->prefix('admin')
3 ->group(function () {
4 Route::resource('users', 'UsersController');
5 });

Route Macros

The Router is macroable, which means if you have a group of routes that you want to provide via a package or reusable groups of route definitions, you can define a macro in a service provider.

For example, maybe you have some shopping route for an e-commerce store that you ship as a package, and allow users to override or customize some parts of the routes:

1// Inside a service provider boot()
2
3public function boot()
4{
5 Route::macro('shopRoutes', function ($prefix) {
6 Route::group([
7 'prefix' => $prefix,
8 'middleware' => ['shopping'],
9 ], function () {
10 Route::get('products/{product}', 'ProductsController@show');
11 // ...
12 });
13 });
14}

Then the consumer could call the macro in a new Laravel application within routes/web.php:

1collect(config('languages'))->each(function ($language) {
2 Route::shopRoutes($language);
3});

Or perhaps an alternate implementation might look like:

1Route::macro('shopRoutes', function ($languages) {
2 Route::group([
3 'prefix' => '/{language}',
4 'middleware' => ['shopping'],
5 'where' => ['language' => implode('|', $languages)],
6 ], function () {
7 Route::get('products/{product}', 'ProductsController@show');
8 // ...
9 });
10});

The macro examples are abstract, but you get the idea. I would suggest that you only use route macros if it makes sense to your use-case. You’ll know when the timing is right!

Debugging Routes

I appreciate that in a Laravel application, the web.php file (and api.php file) is a self-documenting file about the routes to which my application is capable of responding. I prefer to define every route instead of using resources because I appreciate the documentation aspect of this file.

If you find yourself trying to find a route or debugging all possible defined routes, the artisan route:list command is helpful:

1artisan route:list
2+--------+----------+----------+------+---------+--------------+
3| Domain | Method | URI | Name | Action | Middleware |
4+--------+----------+----------+------+---------+--------------+
5| | GET|HEAD | / | | Closure | web |
6| | GET|HEAD | api/user | | Closure | api,auth:api |
7+--------+----------+----------+------+---------+--------------+

The route:list command is useful to see the name of the route and the attached middleware. Which brings me to the next tip, naming routes.

Named Group Routes

A common convention in Laravel is naming routes, which allows you to easily reference the name of the route and avoid hard-coding the root-relative URI in your templates. In some applications hard-coding the URI is fine, in other cases, the named routes allow the following:

1{{ route('admin.users.show', ['user' => $user]) }}
2{{-- /admin/users/2 --}}

When you are defining a group of routes, for example, our admin example, you can also prefix the name of the route on the group:

1Route::namespace('Admin')
2 ->prefix('admin')
3 ->name('admin.')
4 ->group(function () {
5 Route::resource('users', 'UsersController');
6 });

The above prefixed name would generate route names like the following for the users resource controller:

  • admin.users.index
  • admin.users.store
  • admin.users.create
  • admin.users.show
  • admin.users.update
  • admin.users.destroy
  • admin.users.edit

Learn More

Read through the entire routing documentation and the resource controllers section of the controllers documentation. I reference the resource controllers section to try and ensure that most of my routes represent a REST verb and for route naming conventions.

Filed in:

Paul Redmond

Full stack web developer. Author of Lumen Programming Guide and Docker for PHP Developers.