🏠 Home / Hub

Laravel 02 — Routes & Controllers

Routes map URLs to code. Controllers organize that code into classes. Together they form the entry point of every Laravel request.

1. Route Basics — web.php vs api.php

Laravel has two main route files with different purposes:

FilePurposeMiddleware
routes/web.phpBrowser routes — returns HTML viewsweb (sessions, CSRF, cookies)
routes/api.phpAPI routes — returns JSON, statelessapi (rate limiting, no sessions)
routes/console.phpArtisan closure commands
routes/channels.phpWebSocket broadcast channels
API routes are automatically prefixed with /api. So Route::get('/posts', ...) in api.php is reachable at /api/posts.

2. Route Types: GET, POST, PUT, PATCH, DELETE

<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;

// GET — retrieve data / show a page
Route::get('/posts', [PostController::class, 'index']);

// POST — create a resource
Route::post('/posts', [PostController::class, 'store']);

// PUT — replace entire resource
Route::put('/posts/{id}', [PostController::class, 'update']);

// PATCH — partial update
Route::patch('/posts/{id}', [PostController::class, 'update']);

// DELETE — remove a resource
Route::delete('/posts/{id}', [PostController::class, 'destroy']);

// Match any HTTP method
Route::any('/webhook', [WebhookController::class, 'handle']);

// Match specific methods
Route::match(['get', 'post'], '/contact', [ContactController::class, 'handle']);

3. Route Parameters

Required Parameters

// {id} is required — URL must include it
Route::get('/posts/{id}', function ($id) {
    return "Post ID: $id";
});

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

Optional Parameters

// {name?} is optional — has a default value
Route::get('/user/{name?}', function ($name = 'Guest') {
    return "Hello, $name!";
});
// /user        -> "Hello, Guest!"
// /user/Alice  -> "Hello, Alice!"

Parameter Constraints

// Restrict to numeric IDs only
Route::get('/posts/{id}', [PostController::class, 'show'])
    ->where('id', '[0-9]+');

// Restrict to alpha string
Route::get('/user/{name}', [UserController::class, 'show'])
    ->where('name', '[A-Za-z]+');

// Global constraint in RouteServiceProvider
// Route::pattern('id', '[0-9]+');

4. Named Routes

Naming routes lets you generate URLs without hardcoding paths — very useful in forms and redirects.

// Define named route
Route::get('/posts/{id}', [PostController::class, 'show'])->name('posts.show');
Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');

// Generate URL from name
$url = route('posts.show', ['id' => 5]);
// http://your-app.com/posts/5

// Redirect to named route
return redirect()->route('dashboard');
return redirect()->route('posts.show', ['id' => $post->id]);

In Blade templates:

<a href="{{ route('posts.show', $post->id) }}">Read Post</a>
<a href="{{ route('dashboard') }}">Dashboard</a>

5. Route Groups

Prefix Group

// All routes get /admin prefix
Route::prefix('admin')->group(function () {
    Route::get('/users', [AdminController::class, 'users']);   // /admin/users
    Route::get('/settings', [AdminController::class, 'settings']); // /admin/settings
});

Middleware Group

// All routes require authentication
Route::middleware(['auth'])->group(function () {
    Route::get('/dashboard', [DashboardController::class, 'index']);
    Route::resource('posts', PostController::class);
});

Combined Group

Route::prefix('admin')
    ->middleware(['auth', 'admin'])
    ->name('admin.')
    ->group(function () {
        Route::get('/dashboard', [AdminController::class, 'index'])->name('dashboard');
        // Route name = admin.dashboard
        // URL = /admin/dashboard
    });

6. Creating a Controller

# Create a basic controller
php artisan make:controller PostController

# Create a resource controller (with all 7 CRUD methods pre-defined)
php artisan make:controller PostController --resource

# Create API resource controller (no create/edit — no HTML forms)
php artisan make:controller Api/PostController --api

Generated resource controller skeleton:

<?php
namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;

class PostController extends Controller
{
    public function index()    { /* list all */ }
    public function create()   { /* show create form */ }
    public function store(Request $request) { /* save new */ }
    public function show(Post $post)        { /* show one */ }
    public function edit(Post $post)        { /* show edit form */ }
    public function update(Request $request, Post $post) { /* update */ }
    public function destroy(Post $post)     { /* delete */ }
}

7. Resource Controller Methods

MethodHTTP VerbURIRoute NamePurpose
indexGET/postsposts.indexList all posts
createGET/posts/createposts.createShow create form
storePOST/postsposts.storeSave new post
showGET/posts/{id}posts.showDisplay one post
editGET/posts/{id}/editposts.editShow edit form
updatePUT/PATCH/posts/{id}posts.updateUpdate existing post
destroyDELETE/posts/{id}posts.destroyDelete post
// Register all 7 routes in one line
Route::resource('posts', PostController::class);

// Only specific methods
Route::resource('posts', PostController::class)->only(['index', 'show']);

// Exclude specific methods
Route::resource('posts', PostController::class)->except(['destroy']);

8. Route Model Binding

Laravel automatically resolves Eloquent models from route parameters — no manual Post::find($id) needed.

// Without binding (manual lookup)
Route::get('/posts/{id}', function ($id) {
    $post = Post::findOrFail($id);  // throws 404 if not found
    return view('posts.show', compact('post'));
});

// With implicit model binding (automatic — type-hint the model)
Route::get('/posts/{post}', function (Post $post) {
    return view('posts.show', compact('post'));
    // Laravel finds Post where id = {post}
    // Returns 404 automatically if not found
});

// In a controller (same type-hint approach)
public function show(Post $post)
{
    return view('posts.show', compact('post'));
}
The parameter name {post} must match the variable name $post in the method signature for implicit binding to work.

9. Route List Command

Inspect all registered routes with:

php artisan route:list

# Filter by name
php artisan route:list --name=posts

# Filter by URI
php artisan route:list --path=api

# Show middleware
php artisan route:list -v

Example output:

  GET|HEAD   /                    ...
  GET|HEAD   api/posts            posts.index
  POST       api/posts            posts.store
  GET|HEAD   api/posts/{post}     posts.show
  PUT|PATCH  api/posts/{post}     posts.update
  DELETE     api/posts/{post}     posts.destroy
Run php artisan route:cache in production to cache routes for faster resolution. Always run php artisan route:clear after adding new routes.

📌 Study Checklist