Introduction

Routing is how Laravel decides which piece of code handles each URL. This lesson covers the basic Route::get, Route::post, and friends plus route parameters with regex constraints — the vocabulary every Laravel route builds on.

Key Concepts

  • Route file: routes/web.php handles sessions and CSRF; routes/api.php is stateless and installed via install:api.
  • HTTP verb helpers: Route::get, post, put, patch, delete, options, match, any.
  • Route parameters: {id} captures a URL segment and injects it into the action.
  • Constraints: ->where(...), ->whereNumber(...), ->whereAlpha(...) limit what parameters can match.
  • Global patterns: Route::pattern('id', '[0-9]+') applies a constraint to every {id} parameter.

Real World Context

Every request into a Laravel app lands on a route definition. A sloppy routes file leads to ambiguous URLs, slow lookups, and security holes where the wrong action runs on the wrong URL. Getting routes right is the foundation everything else stands on.

Deep Dive

Routing is the mechanism that maps URLs to specific code in your application. When a user visits /users, how does Laravel know what to display? Routes define this mapping.

What is a Route?

A route consists of:

  1. An HTTP method (GET, POST, PUT, DELETE, etc.)
  2. A URI pattern (/users, /posts/{id})
  3. An action (closure or controller method)
php
// When someone visits /hello via GET request
Route::get('/hello', function () {
    return 'Hello, World!';
});

Route Files

Laravel organizes routes into separate files:

routes/
├── web.php     # Web routes with sessions, CSRF
├── api.php     # API routes (stateless)
├── console.php # Artisan commands
└── channels.php # Broadcast channels
routes/web.php

For traditional web pages with sessions and CSRF protection:

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

Route::get('/dashboard', function () {
    return view('dashboard');
})->middleware(['auth']);
routes/api.php

For stateless API endpoints. Routes are automatically prefixed with /api:

php
// routes/api.php
// This becomes /api/users
Route::get('/users', function () {
    return User::all();
});

Basic Route Definition

GET Requests

For retrieving data:

php
// Visit /users to see all users
Route::get('/users', function () {
    return view('users.index', ['users' => User::all()]);
});

// Visit /about to see the about page
Route::get('/about', function () {
    return view('about');
});
POST Requests

For submitting data:

php
Route::post('/users', function (Request $request) {
    User::create($request->all());
    return redirect('/users');
});
Other HTTP Methods
php
// Update a resource
Route::put('/users/{id}', function ($id) {
    // Update user
});

Route::patch('/users/{id}', function ($id) {
    // Partial update
});

// Delete a resource
Route::delete('/users/{id}', function ($id) {
    // Delete user
});

// Match multiple methods
Route::match(['get', 'post'], '/form', function () {
    // Handle GET or POST
});

// Match ANY method
Route::any('/webhook', function () {
    // Handle any HTTP method
});

Route Parameters

Capture segments of the URI:

php
// Required parameter
Route::get('/users/{id}', function (string $id) {
    return "User ID: {$id}";
});
// /users/1 → "User ID: 1"
// /users/42 → "User ID: 42"
// /users → 404 Not Found

// Optional parameter
Route::get('/users/{name?}', function (?string $name = 'Guest') {
    return "Hello, {$name}";
});
// /users → "Hello, Guest"
// /users/John → "Hello, John"

// Multiple parameters
Route::get('/posts/{post}/comments/{comment}', function ($postId, $commentId) {
    return "Post {$postId}, Comment {$commentId}";
});

Route Constraints

Limit what parameters can match:

php
// Only numeric IDs
Route::get('/users/{id}', function ($id) {
    return User::findOrFail($id);
})->where('id', '[0-9]+');

// Only alphabetic names
Route::get('/users/{name}', function ($name) {
    return "Hello, {$name}";
})->where('name', '[A-Za-z]+');

// Multiple constraints
Route::get('/posts/{id}/{slug}', function ($id, $slug) {
    // ...
})->where(['id' => '[0-9]+', 'slug' => '[a-z-]+']);

// Helper methods
Route::get('/users/{id}', $action)->whereNumber('id');
Route::get('/users/{name}', $action)->whereAlpha('name');
Route::get('/users/{name}', $action)->whereAlphaNumeric('name');
Route::get('/users/{uuid}', $action)->whereUuid('uuid');

Global Constraints

Apply constraints to all routes in AppServiceProvider:

php
public function boot(): void
{
    Route::pattern('id', '[0-9]+');
}

// Now all {id} parameters must be numeric

Common Pitfalls

  1. Not constraining numeric parameters — /users/{id} happily matches /users/drop-table. Constrain with ->whereNumber('id').
  2. Defining routes in the wrong file — routes/web.php applies sessions and CSRF; routes/api.php is stateless. Putting a web form route in api.php breaks CSRF protection.

Best Practices

  1. Prefer controller-method references — [UserController::class, 'show'] beats closures once the route has any real logic.
  2. Use whereNumber, whereAlpha, whereUuid — They are clearer than raw regex and cover 90% of real constraints.

Summary

  • Routes live in routes/web.php and routes/api.php (the API file is added via install:api).
  • Route::get, post, put, patch, delete cover all HTTP verbs.
  • Parameters use {name} syntax and are injected into the action.
  • ->where() plus helpers like whereNumber constrain what parameters can match.
  • Route::pattern(...) applies a global constraint.
✓ Completed