When it comes to the backend, developers eventually encounter routes. Routes can be considered the backbone of the backend since every request the server receives is redirected to a controller through a routing list that maps requests to controllers or actions.
Laravel hides many implementation details for us and comes with a lot of syntactic sugar to help both new and experienced developers develop their web applications.
Let’s take a close look at how to manage routes in Laravel.
Backend Routing and Cross-Site Scripting in Laravel
On a server, there exist both public and private routes. Public routes can be a cause of concern due to the possibility for cross-site scripting (XSS), a type of injection attack that can leave you and your users vulnerable to malicious actors.
The problem is that a user can be redirected from a route that doesn’t require a session token to one that does — and they’ll still have access without the token.
The simplest way to solve this issue is to enforce a new HTTP header, adding “referrer” to the route to mitigate this scenario:
'main' => [
'path' => '/main',
'referrer' => 'required,refresh-empty',
'target' => Controller\DashboardController::class . '::mainAction'
]
Laravel Basic Routing
In Laravel, routes allow users to route the appropriate request to the desired controller. The most basic Laravel Route accepts a Uniform Asset Identifier (your route path) and a closure which can be both a function or a class.
In Laravel, routes are created inside the web.php and api.php files. Laravel comes with two routes by default: one for the WEB and one for the API.
These routes reside in the routes/ folder, but they are loaded in the Providers/RouteServiceProvider.php.
Instead of doing this, we can load the routes directly inside RouteServiceProvider.php, skipping the routes/ folder altogether.
Redirects
When we define a route, we’ll usually want to redirect the user that accesses it, and the reasons for this vary a lot. It may be because it’s a deprecated route and we have changed the backend or the server, or it may be because we want to install two-factor authentication (2FA), and so on.
Laravel has an easy way of doing this. Thanks to the framework’s simplicity, we can use the redirect method on the Route facade, which accepts the entry route and the route to be redirected to.
Optionally, we can give the status code for the redirect as the third parameter. The permanentRedirect
method will do the same as the redirect
method, except it will always return a 301 status code:
// Simple redirect
Route::redirect("/class", "/myClass");
// Redirect with custom status
Route::redirect("/home", "/office", 305);
// Route redirect with 301 status code
Route::permanentRedirect("/home", "office");
Inside the redirect routes we are forbidden to use the “destination” and “status” keywords as parameters as they are reserved by Laravel.
// Illegal to use
Route::redirect("/home", "/office/{status}");
Views
Views are the .blade.php files that we use to render the frontend of our Laravel application. It uses the blade templating engine, and it is the default way to build a full-stack application using only Laravel.
If we want our route to return a view, we can simply use the view method on the Route facade. It accepts a route parameter, a view name, and an optional array of values to be passed to the view.
// When the user accesses my-domain.com/homepage
// the homepage.blade.php file will be rendered
Route::view("/homepage", "homepage");
Let’s assume our view wants to say “Hello, {name}
” by passing an optional array with that parameter. We can do just that with the following code (if the missing parameter is required in the view, the request will fail and throw an error):
Route::view('/homepage', 'homepage', ['name' => "Kinsta"]);
Route List
As your application grows in size, so will the number of requests that need to be routed. And with a great volume of information can come great confusion.
This is where the artisan route:list command
can help us. It provides an overview of all the routes that are defined in the application, their middlewares, and controllers.
php artisan route:list
It will display a list of all routes without the middlewares. For this, we have to use the -v
flag:
php artisan route:list -v
In a situation where you may be using domain-driven design where your routes have specific names in their paths, you can make use of the filtering capabilities of this command like so:
php artisan route:list –path=api/account
This will show only the routes that start with api/account.
On the other hand, we can instruct Laravel to exclude or include third-party defined routes by using the –except-vendor
or –only-vendor
options.
Route Parameters
Sometimes you might need to capture segments of the URI with the route, like a user ID or token. We can do this by defining a route parameter, which is always encased within curly braces ({}
) and should only consist of alphabetic characters.
If our routes have dependencies inside their callbacks, the Laravel service container will automatically inject them:
use Illuminate\Http\Request;
use Controllers/DashboardController;
Route::post('/dashboard/{id}, function (Request $request, string $id) {
return 'User:' . $id;
}
Route::get('/dashboard/{id}, DashboardController.php);
Required Parameters
Laravel’s required parameters are parameters in routes that we aren’t allowed to skip when we make a call. Otherwise, an error will be thrown:
Route::post("/gdpr/{userId}", GetGdprDataController.php");
Now inside the GetGdprDataController.php we will have direct access to the $userId parameter.
public function __invoke(int $userId) {
// Use the userId that we received…
}
A route can take any numbers of parameters. They are injected in the route callbacks/controllers based on the order in which they’re listed:
// api.php
Route::post('/gdpr/{userId}/{userName}/{userAge}', GetGdprDataController.php);
// GetGdprDataController.php
public function __invoke(int $userId, string $userName, int $userAge) {
// Use the parameters…
}
Optional Parameters
In a situation where we want to do something on a route when only a parameter is present and nothing else, all without affecting the entire application, we can add an optional parameter. These optional parameters are denoted by the ?
appended to them:
Route::get('/user/{age?}', function (int $age = null) {
if (!$age) Log::info("User doesn't have age set");
else Log::info("User's age is " . $age);
}
Route::get('/user/{name?}', function (int $name = "John Doe") {
Log::info("User's name is " . $name);
}
Route Wildcard
Laravel provides a way for us to filter what our optional or required parameters should look like.
Say we want a string of a user ID. We can validate it like so on the route level using the where
method.
The where
method accepts the name of the parameter and the regex rule that will be applied on the validation. By default, it takes the first parameter, but if we have many, we can pass an array with the name of the parameter as the key and the rule as the value, and Laravel will parse them all for us:
Route::get('/user/{age}', function (int $age) {
//
}->where('age', '[0-9]+');
Route::get('/user/{age}', function (int $age) {
//
}->where('[0-9]+');
Route::get('/user/{age}/{name}', function (int $age, string $name) {
//
}->where(['age' => '[0-9]+', 'name' => '[a-z][A-z]+');
We can take this a step further and apply validation on all the routes in our application by using the pattern
method on the Route
facade:
Route::pattern('id', '[0-9]+');
This will valide every id
parameter with this regex expression. And once we define it, it will be automatically applied to all routes using that parameter name.
As we can see, Laravel is using the /
character as a separator in the path. If we want to use it in the path, we have to explicitly allow it to be part of our placeholder using a where
regex.
Route::get('/find/{query}', function ($query) {
//
})->where('query', , '.*');
The only downside is that it will be supported only in the last route segment.
Named Routes
As the name suggests, we can name routes, which makes it convenient to generate URLs or redirect for specific routes.
How To Create Named Routes
A simple way to create a named route is provided by the name
method chained on the Route
facade. Each route’s name should be unique:
Route::get('/', function () {
})->name("homepage");
Route Groups
Route groups allow you to share route attributes like middlewares across a large number of routes without needing to re-define it on each and every route.
Middleware
Assigning a middleware to all routes we have allows us to combine them in a group, first by using the group
method. One thing to consider is that the middlewares are executed in the order in which they are applied to the group:
Route:middleware(['AuthMiddleware', 'SessionMiddleware'])->group(function () {
Route::get('/', function() {} );
Route::post('/upload-picture', function () {} );
});
Controllers
When a group utilizes the same controller, we can use the controller
method to define the common controller for all the routes within that group. Now we have to specify the method that the route will call.
Route::controller(UserController::class)->group(function () {
Route::get('/orders/{userId}', 'getOrders');
Route::post('/order/{id}', 'postOrder');
});
Subdomain Routing
A subdomain name is a piece of additional information added to the beginning of a website’s domain name. This allows websites to separate and organize their content for specific functions, such as online stores, blogs, presentations, and so on from the rest of the website.
Our routes can be used to handle subdomain routing. We can catch the domain and a portion of the subdomain for usage in our controller and route. With the help of the domain
method on the Route
facade, we can group our routes under a single domain:
Route::domain('{store}.enterprise.com')->group(function() {
Route::get('order/{id}', function (Account $account, string $id) {
// Your Code
}
});
Prefixes and Name Prefixes
Whenever we have a group of routes, instead of modifying them one by one, we can make use of the extra utilities that Laravel provides, such as prefix
and name
on the Route
facade.
The prefix
method can be used to prefix each route in the group with a given URI, and the name
method can be used to prefix each route name with a given string.
This allows us to create new things like admin routes without being required to modify each and every name or prefix to identify them:
Route::name('admin.")->group(function() {
Route::prefix("admin")->group(function() {
Route::get('/get')->name('get');
Route::put('/put')->name(put');
Route::post('/post')->name('post');
});
});
Now the URIs for these routes will be admin/get
, admin/put
, admin/post
, and the names admin.get
, admin.put
, and admin.post
.
Route Caching
When deploying the application to production servers, a good Laravel developer will take advantage of Laravel’s route cache.
What Is Route Caching?
Route caching decreases the amount of time it takes to register all the application routes.
Running php artisan route:cache
an instance of Illuminate/Routing/RouteCollection
is generated, and after being encoded, the serialized output is written to bootstrap/cache.routes.php
.
Now any other request will load this cache file if it exists. Therefore, our application no longer has to parse and convert entries from the route file into Illuminate/Routing/Route
objects in Illuminate/Routing/RouteCollection
.
Why It’s Important To Use Route Caching
By not using the route caching feature that Laravel provides, your application risks running more slowly than it could be, which could in turn decrease sales, user retention, and trust in your brand.
Depending on the scale of your project and how many routes there are, running a simple route caching command can speed up your application by anywhere from 130% to 500% — a massive gain for nearly no effort.
Summary
Routing is the backbone of backend development. The Laravel framework excels at this by providing a verbose way of defining and managing routes.
Development can indeed be accessible for everyone and help speed up an application just by virtue of it being built in Laravel.
What other tricks and tips have you encountered regarding Laravel routes? Let us know in the comments section!
Leave a Reply