DEV Community

David Berri
David Berri

Posted on • Originally published at dberri.com on

The different ways to do routing in Laravel

Routing in Laravel is very flexible. You can define the routes to your app in so many ways, with so many modifiers, each with a different purpose or better suited to a specific use case. Today, I want to show you a few ways that helped me and that I use very frequently while working with Laravel.

The most basic one, is the first one shown in the documentation:

use Illuminate\Support\Facades\Route;

Route::get('/greeting', function () {
    return 'Hello World';
});
Enter fullscreen mode Exit fullscreen mode

This uses a closure and means that when a user hits navigates to [your app host]/greeting they will be greeted with a simple "Hello World" string. Technically, you can implement your entire application in this closure. Nothing will stop you if you try to add all your bussiness logic in there, but of course that's not very effective and if you have more routes it becomes very ugly.

When you just create a new Laravel application, it already comes with one basic route defined for / which looks like this:

use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return view('welcome');
});
Enter fullscreen mode Exit fullscreen mode

This is a more elaborate version of the first one, but in this case, it is going to return a view. This view is a Blade file located in resources/views which is named welcome.blade.php. So, now you can start composing views using blade and if there's not much going on in your view (e.g. it's a static page) you don't need to create a controller just to return a view.

Speaking of controllers, there are a few ways you can point your route to a controller or controller method. The default way that appears in the documentation looks like this:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::get('/user', [UserController::class, 'index']);
Enter fullscreen mode Exit fullscreen mode

When a request hits /user the method "index" in the UserController class will be called. Previously, I used to define routes with a different syntax (which as far as I know is still valid and working in Laravel 8:

use Illuminate\Support\Facades\Route;

Route::get('/user', 'UserController@index');
Enter fullscreen mode Exit fullscreen mode

Notice that it's the same controller and method, but instead of an array, you pass a string declaring the controller and method separated by a @ symbol. Another thing you'll notice is that we don't need the use statement for this class because Laravel will automatically try to find that the UserController class in the App\Http\Controllers namespace. Even though this works the same way as the previous example, I prefer the previous one because the it comes with some IDE niceties, like clicking on a class and navigating to its definition, or if you move the class file to another directory, it will warn you the use statement is not valid anymore.

Just a quick and related note, you can do the same with model relationships:

class User {
    public function books() {
        return $this->hasMany('Book');
    }
}

use App\Book;

class User {
    public function books() {
        return $this->hasMany(Book::class);
    }
}
Enter fullscreen mode Exit fullscreen mode

Invocable controllers

Now, if your controller is a little complex and you use it for a single action with the __invoke method, you don't need to pass an array with controller and method to the route declaration, you can just pass the class as an argument, like this:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::get('/user', UserController::class);
Enter fullscreen mode Exit fullscreen mode

Resource routes

You can also do a similar route declaration with resource controllers. This type of controller is that classic "CRUD" class, where you have index, show, create, store, edit, update, and destroy methods. Then you can define the route to this controller like this:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::resource('users', UserController::class);
Enter fullscreen mode Exit fullscreen mode

This will create a route for each of the controller methods and will name them, just like if you had created them manually following this pattern:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::get('/users', [UserController::class, 'index'])->name('users.index');
Route::get('/users/{user}', [UserController::class, 'show'])->name('users.show');
Route::get('/users/create', [UserController::class, 'create'])->name('users.create');
Route::post('/users', [UserController::class, 'store')->name('users.store');
Route::get('/users/{user}/edit', [UserController::class, 'edit'])->name('users.edit');
Route::patch('/users/{user}', [UserController::class, 'update'])->name('users.update');
Route::delete('/users/{user}', [UserController::class, 'destroy'])->name('users.destroy');
Enter fullscreen mode Exit fullscreen mode

And if you don't want a few of those routes you can tell the resource method which ones you don't need:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::resource('users', UserController::class)->except(['edit', 'udpate']);
Enter fullscreen mode Exit fullscreen mode

Or the other way around, if you only need a few routes:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::resource('users', UserController::class)->only(['index', 'show']);
Enter fullscreen mode Exit fullscreen mode

And finally, if you are developing an API, you probably don't need the create and edit routes which usually navigate the user to a form. If that's the case, you can define the routes like this:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::apiResource('users', UserController::class);
Enter fullscreen mode Exit fullscreen mode

There is also a plural form of each one of these two methods, if you want to define multiple resource controllers:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;
use App\Http\Controllers\BookController;

Route::resources([
    'users' => UserController::class
    'books' => BookController::class
]);

// or

Route::apiResources([
    'users' => UserController::class
    'books' => BookController::class
]);
Enter fullscreen mode Exit fullscreen mode

One last case we can cover is nested resources. For example, if you want to update a specific book of a specific user, you could define the route as:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserBookController;

Route::update('/users/{user}/books/{book}', [UserBookController::class, 'update']);
Enter fullscreen mode Exit fullscreen mode

Or, using the resource syntax:

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserBookController;

Route::resource('users.books', UserBookController::class);
Enter fullscreen mode Exit fullscreen mode

Much cleaner!

And that's it! I mean, there is a lot more to cover like middlewares, route grouping, namespaces, Route Model Binding, rate limiting, and so on. But I'll write more about those in the future. If you're curious and want to dig deeper, I suggest you dive into Laravel's documentation. See you next time 👋

Top comments (0)