Laravel Routing¶
Routes map HTTP requests to controller actions. Defined in routes/web.php (session/CSRF) and routes/api.php (stateless). Routes support parameters, named references, grouping, and resource CRUD conventions. Controllers organize route handlers by domain. Closely tied to laravel middleware for access control and laravel blade templates for view rendering.
Key Facts¶
routes/web.php- web routes with session, CSRF protection, cookie middlewareroutes/api.php- API routes, stateless,/apiprefix by default- Route methods:
Route::get(),::post(),::put(),::patch(),::delete(),::any(),::match() - Named routes:
->name('posts.index')- used inroute('posts.index')helper for URL generation - Route parameters:
{id}required,{id?}optional - Route model binding: type-hint Eloquent model in controller to auto-resolve by ID
- Resource routes:
Route::resource('posts', PostController::class)generates 7 CRUD routes - Route groups: share middleware, prefix, namespace across multiple routes
php artisan route:listshows all registered routes
Patterns¶
Basic routes¶
<?php
use App\Http\Controllers\PostController;
use Illuminate\Support\Facades\Route;
// Closure route (simple pages)
Route::get('/', function () {
return view('welcome');
});
// Controller route
Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
Route::get('/posts/{post}', [PostController::class, 'show'])->name('posts.show');
Route::post('/posts', [PostController::class, 'store'])->name('posts.store');
Route::put('/posts/{post}', [PostController::class, 'update'])->name('posts.update');
Route::delete('/posts/{post}', [PostController::class, 'destroy'])->name('posts.destroy');
Resource routes (CRUD)¶
<?php
// Generates all 7 RESTful routes
Route::resource('posts', PostController::class);
// Equivalent to:
// GET /posts -> index posts.index
// GET /posts/create -> create posts.create
// POST /posts -> store posts.store
// GET /posts/{post} -> show posts.show
// GET /posts/{post}/edit -> edit posts.edit
// PUT /posts/{post} -> update posts.update
// DELETE /posts/{post} -> destroy posts.destroy
// Partial resource
Route::resource('posts', PostController::class)->only(['index', 'show']);
Route::resource('posts', PostController::class)->except(['destroy']);
// API resource (no create/edit - those are form views)
Route::apiResource('posts', PostController::class);
Route groups¶
<?php
// Admin routes with prefix, middleware, and controller namespace
Route::prefix('admin')
->middleware(['auth', 'admin'])
->name('admin.')
->group(function () {
Route::get('/', [Admin\MainController::class, 'index'])->name('main.index');
Route::resource('posts', Admin\PostController::class);
Route::resource('categories', Admin\CategoryController::class);
});
// Generates: admin/posts, admin/categories, etc.
// Names: admin.posts.index, admin.categories.index, etc.
Route model binding¶
<?php
// Implicit binding - Laravel resolves {post} to Post model by ID
Route::get('/posts/{post}', function (Post $post) {
return view('posts.show', compact('post'));
});
// Automatically returns 404 if post not found
// Custom column binding
Route::get('/posts/{post:slug}', function (Post $post) {
return $post; // resolved by slug column
});
Controllers¶
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function index()
{
$posts = Post::latest()->paginate(15);
return view('posts.index', compact('posts'));
}
public function show(Post $post)
{
return view('posts.show', compact('post'));
}
public function store(Request $request)
{
$validated = $request->validate([
'title' => 'required|max:255',
'body' => 'required',
]);
Post::create($validated);
return redirect()->route('posts.index')
->with('success', 'Post created.');
}
public function destroy(Post $post)
{
$post->delete();
return redirect()->route('posts.index')
->with('success', 'Post deleted.');
}
}
URL generation¶
<?php
// In Blade templates
<a href="{{ route('posts.show', $post) }}">View</a>
<a href="{{ route('posts.edit', ['post' => $post->id]) }}">Edit</a>
// In controllers
return redirect()->route('admin.main.index');
return redirect()->back()->with('error', 'Not found');
// Asset URLs
<link href="{{ asset('assets/admin/css/adminlte.css') }}" rel="stylesheet">
Gotchas¶
| Symptom | Cause | Fix |
|---|---|---|
Route [name] not defined | Typo in route name or route not registered | Run php artisan route:list to verify |
Wrong route matches (e.g., posts/create hits posts/{post}) | Route order matters - specific routes before parameterized | Place posts/create before posts/{post} |
| 405 Method Not Allowed | Form uses GET but route expects POST, or missing @method('PUT') | Add @method('PUT') or @method('DELETE') to form |
| Route model binding returns 404 | Model not found by ID (or soft deleted) | Check database or use withTrashed() in route binding |
| CSRF token mismatch on POST | Missing @csrf directive in form | Add @csrf inside <form> tag |
| Route cache stale after changes | Route cache was generated before new routes | Run php artisan route:clear |
See Also¶
- laravel middleware - protecting routes with auth, admin checks
- laravel blade templates - rendering views from controllers
- laravel validation - validating request data
- https://laravel.com/docs/11.x/routing
- https://laravel.com/docs/11.x/controllers