Laravel Route Tips to Improve Your Routing
Published on by Paul Redmond
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:
Route::namespace('Admin')->group(function () { // Controllers Within The "App\Http\Controllers\Admin" Namespace});
This is exactly the technique used in the RouteServiceProvider
found in each Laravel project:
protected function mapWebRoutes(){ Route::middleware('web') ->namespace($this->namespace) ->group(base_path('routes/web.php'));}
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:
php artisan make:controller -r Admin/UsersController
Within our previous routing example, our definition might look like this in the routes/web.php
file:
Route::namespace('Admin') ->prefix('admin') ->group(function () { Route::resource('users', 'UsersController'); });
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:
// Inside a service provider boot() public function boot(){ Route::macro('shopRoutes', function ($prefix) { Route::group([ 'prefix' => $prefix, 'middleware' => ['shopping'], ], function () { Route::get('products/{product}', 'ProductsController@show'); // ... }); });}
Then the consumer could call the macro in a new Laravel application within routes/web.php
:
collect(config('languages'))->each(function ($language) { Route::shopRoutes($language);});
Or perhaps an alternate implementation might look like:
Route::macro('shopRoutes', function ($languages) { Route::group([ 'prefix' => '/{language}', 'middleware' => ['shopping'], 'where' => ['language' => implode('|', $languages)], ], function () { Route::get('products/{product}', 'ProductsController@show'); // ... });});
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:
artisan route:list+--------+----------+----------+------+---------+--------------+| Domain | Method | URI | Name | Action | Middleware |+--------+----------+----------+------+---------+--------------+| | GET|HEAD | / | | Closure | web || | GET|HEAD | api/user | | Closure | api,auth:api |+--------+----------+----------+------+---------+--------------+
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:
{{ route('admin.users.show', ['user' => $user]) }}{{-- /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:
Route::namespace('Admin') ->prefix('admin') ->name('admin.') ->group(function () { Route::resource('users', 'UsersController'); });
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.