Clean up your Laravel routes

Using some Laravel magic to reduce controller methods

12 June 2022

When you create a new Laravel project, there is 1 route in your web.php:

// file: web.php
Route::get('/', function () {
    return view('welcome');
});

So you might assume that this is the best way to do it, but that is not necessarily the case.

Replacing the closure with a controller method

A neater way would be to replace the closure with a controller method. The implication, in fact, is that it can then be cached. That is not possible with closures. It would look like this:

// file: web.php

use App\Http\Controllers\HomeController;

Route::get('/', [HomeController::class, 'index']);

Of course, you then need the corresponding controller:

// file: app/Http/Controllers/HomeController.php

use App\Http\Controllers\Controller;

class HomeController extends Controller
{
    public function index()
    {
        return view('welcome');
    }
}

But that's a bit excessive for just a view, right?

While this may be able to be cached, it is a bit over the top. What if you have 3 pages on your website that are not part of your functionalities? They are just there for information and contain no logic.

Then it gets a little excessive:

// file: web.php

use App\Http\Controllers\HomeController;

Route::get('/', [HomeController::class, 'index']);
Route::get('/about', [HomeController::class, 'about']);
Route::get('/contact', [HomeController::class, 'contact']);
// file: app/Http/Controllers/HomeController.php

use App\Http\Controllers\Controller;

class HomeController extends Controller
{
    public function index()
    {
        return view('welcome');
    }

    public function about()
    {
        return view('about');
    }

    public function contact()
    {
        return view('contact');
    }
}

Introducing... Route::view!

Fortunately, Laravel wouldn't be Laravel if there wasn't a neater way to solve this. This way is simply described in the documentation, yet it is often overlooked.

If your route only returns a view, you can describe that directly in your route file. This allows you to skip the controller. The first argument is the URI and the second argument is the view name.

// file: web.php

Route::view('/', 'welcome');

If you need to, you can also add parameters to it as the third argument.

// file: web.php

Route::view('/', 'welcome', ['name' => 'John']);

And that's all! No more closures and no more messy, redundant controller methods!

Wait! So why is the default route not using Route::view?

There is a very simple reason for this: Taylor finds this easier when debugging. πŸ‘‡

There is, of course, nothing to argue with that.

When you create a new Laravel project, there is 1 route in your web.php:

// file: web.php
Route::get('/', function () {
    return view('welcome');
});

So you might assume that this is the best way to do it, but that is not necessarily the case.

Replacing the closure with a controller method

A neater way would be to replace the closure with a controller method. The implication, in fact, is that it can then be cached. That is not possible with closures. It would look like this:

// file: web.php

use App\Http\Controllers\HomeController;

Route::get('/', [HomeController::class, 'index']);

Of course, you then need the corresponding controller:

// file: app/Http/Controllers/HomeController.php

use App\Http\Controllers\Controller;

class HomeController extends Controller
{
    public function index()
    {
        return view('welcome');
    }
}

But that's a bit excessive for just a view, right?

While this may be able to be cached, it is a bit over the top. What if you have 3 pages on your website that are not part of your functionalities? They are just there for information and contain no logic.

Then it gets a little excessive:

// file: web.php

use App\Http\Controllers\HomeController;

Route::get('/', [HomeController::class, 'index']);
Route::get('/about', [HomeController::class, 'about']);
Route::get('/contact', [HomeController::class, 'contact']);
// file: app/Http/Controllers/HomeController.php

use App\Http\Controllers\Controller;

class HomeController extends Controller
{
    public function index()
    {
        return view('welcome');
    }

    public function about()
    {
        return view('about');
    }

    public function contact()
    {
        return view('contact');
    }
}

Introducing... Route::view!

Fortunately, Laravel wouldn't be Laravel if there wasn't a neater way to solve this. This way is simply described in the documentation, yet it is often overlooked.

If your route only returns a view, you can describe that directly in your route file. This allows you to skip the controller. The first argument is the URI and the second argument is the view name.

// file: web.php

Route::view('/', 'welcome');

If you need to, you can also add parameters to it as the third argument.

// file: web.php

Route::view('/', 'welcome', ['name' => 'John']);

And that's all! No more closures and no more messy, redundant controller methods!

Wait! So why is the default route not using Route::view?

There is a very simple reason for this: Taylor finds this easier when debugging. πŸ‘‡

There is, of course, nothing to argue with that.