404 Not Found

404 Not Found


nginx

A Detailed Explanation of the Laravel Routing System

Routes are Laravel's "front desk"—every HTTP request first checks in here before being routed to the corresponding controller method.

1. What You'll Learn


2. A Product Manager's True Story

(1) Pain Point: Chaotic URL Structures Lead to an SEO Disaster

Alice designed over 30 pages for ShopMetrics, but the URL naming convention was completely haphazard: /shop_view.php?id=5, /admin-users-list, and /api/getData were all mixed together. Google's crawler was extremely inefficient, and when users shared links, the address bar displayed a string of question mark parameters. When Bob restructured the backend and changed a single URL, all 15 hard-coded instances on the front end returned 404 errors.

(2) Solutions for Laravel Routing

Laravel routing uses declarative syntax to define URL rules, supporting naming, grouping, and parameter constraints; changes made in one place automatically take effect globally.

PHP
// routes/web.php — Clean, named, RESTful routes
Route::get('/shops/{slug}', [ShopController::class, 'show'])
    ->name('shops.show')
    ->where('slug', '[a-z0-9-]+');

// Generate URL by name — never hardcode
$url = route('shops.show', ['slug' => 'alice-store']);
// => /shops/alice-store

(3) Revenue

Alice standardized ShopMetrics' URL rules using named routes, resulting in a 30% increase in SEO rankings. When Bob refactored the URLs, he only needed to update the route definitions; the front end route() automatically generated the new URLs, resulting in zero 404 errors.


3. Basic Routing

(1) HTTP Verb Routing

Laravel provides a corresponding route method for each HTTP verb:

PHP
// routes/web.php
Route::get('/shops', [ShopController::class, 'index']);
Route::post('/shops', [ShopController::class, 'store']);
Route::put('/shops/{id}', [ShopController::class, 'update']);
Route::patch('/shops/{id}', [ShopController::class, 'updateStatus']);
Route::delete('/shops/{id}', [ShopController::class, 'destroy']);
HTTP Verb Purpose Idempotency Typical Operations
GET Retrieve Resource List/Details
POST Create Resource Add
PUT Full Update Replace
PATCH Partial Update Status Change
DELETE Delete Resource Delete

(2) "match" and "any" Routes

PHP
// Match multiple verbs
Route::match(['get', 'post'], '/shops/search', [ShopController::class, 'search']);

// Any verb
Route::any('/fallback', [FallbackController::class, 'handle']);

(1) ▶ Example: ShopMetrics Basic Route Definitions

PHP
// routes/web.php
Route::get('/', [HomeController::class, 'index'])->name('home');
Route::get('/about', [AboutController::class, 'index'])->name('about');
Route::get('/pricing', [PricingController::class, 'index'])->name('pricing');
Route::get('/contact', [ContactController::class, 'create'])->name('contact.create');
Route::post('/contact', [ContactController::class, 'store'])->name('contact.store');

Output:

TEXT
// Execution Successful

4. Routing Parameters and Constraints

(1) Required Parameters

PHP
Route::get('/shops/{id}', [ShopController::class, 'show']);
Route::get('/tenants/{tenant}/shops/{shop}', [ShopController::class, 'showForTenant']);

(2) Optional Parameters

PHP
Route::get('/reports/{type?}', [ReportController::class, 'index']);
// /reports → type = null
// /reports/sales → type = 'sales'

(3) Regular Expressions

PHP
// Numeric ID only
Route::get('/shops/{id}', [ShopController::class, 'show'])
    ->where('id', '[0-9]+');

// Slug format: lowercase, numbers, hyphens
Route::get('/shops/{slug}', [ShopController::class, 'showBySlug'])
    ->where('slug', '[a-z0-9-]+');

// Multiple constraints
Route::get('/tenants/{tenant}/orders/{id}', [OrderController::class, 'show'])
    ->where(['tenant' => '[a-z0-9-]+', 'id' => '[0-9]+']);
Constraint Method Usage Description
where() Single-parameter regular expression Most flexible
whereNumber() Numbers only Equivalent to where('id', '[0-9]+')
whereAlpha() Letters only Equivalent to where('name', '[a-zA-Z]+')
whereAlphaNumeric() Letters + Numbers Equivalent where('name', '[a-zA-Z0-9]+')
whereUuid() UUID Format Automatic UUID v4 Validation

(1) ▶ Example: ShopMetrics Routes with Constraints

PHP
// routes/web.php
Route::get('/shops/{id}', [ShopController::class, 'show'])
    ->whereNumber('id');

Route::get('/categories/{slug}', [CategoryController::class, 'show'])
    ->where('slug', '[a-z0-9-]+');

Route::get('/tenants/{tenant}/dashboard', [DashboardController::class, 'index'])
    ->where('tenant', '[a-z0-9-]+');

Output:

TEXT
// Execution Successful

5. Routing Groups

Route grouping allows multiple routes to share configurations (middleware, prefixes, namespaces, etc.), thereby avoiding code duplication.

(1) Middleware Grouping

PHP
Route::middleware(['auth', 'tenant.resolve'])->group(function () {
    Route::get('/dashboard', [DashboardController::class, 'index']);
    Route::get('/shops', [ShopController::class, 'index']);
    Route::get('/orders', [OrderController::class, 'index']);
});

(2) Prefix Grouping

PHP
Route::prefix('admin')->group(function () {
    Route::get('/users', [AdminUserController::class, 'index']);
    Route::get('/settings', [AdminSettingController::class, 'index']);
    // Full URL: /admin/users, /admin/settings
});

(3) Name Grouping

PHP
Route::name('admin.')->group(function () {
    Route::get('/users', [AdminUserController::class, 'index'])->name('users');
    // Route name: admin.users
});

(4) Combination and Grouping

PHP
Route::prefix('admin')
    ->middleware(['auth', 'admin'])
    ->name('admin.')
    ->group(function () {
        Route::get('/users', [AdminUserController::class, 'index'])->name('users');
        Route::get('/plans', [AdminPlanController::class, 'index'])->name('plans');
        // URL: /admin/users, name: admin.users
    });

(1) ▶ Example: ShopMetrics Multitenant Routing Groups

PHP
// routes/web.php — Tenant-aware routes
Route::middleware(['auth', 'tenant.resolve'])->prefix('/{tenant}')->group(function () {
    Route::get('/dashboard', [TenantDashboardController::class, 'index'])
        ->name('tenant.dashboard');
    Route::resource('/shops', ShopController::class);
    Route::resource('/orders', OrderController::class);
    Route::resource('/products', ProductController::class);
});

Output:

TEXT
// Execution Successful

6. Route Naming and URL Generation

(1) Named Routes

PHP
Route::get('/shops/{id}', [ShopController::class, 'show'])
    ->name('shops.show');

(2) Generate a URL

PHP
// In Blade templates or controllers
$url = route('shops.show', ['id' => 5]);
// => http://shopmetrics.test/shops/5

// With query parameters
$url = route('shops.index', ['sort' => 'name', 'page' => 2]);
// => http://shopmetrics.test/shops?sort=name&page=2
Function Purpose Example
route() Generate a named route URL route('shops.show', 5)
url() Generate Absolute URL url('/shops')
action() Generated based on the controller method action([ShopController::class, 'show'], 5)

(1) ▶ Example: Using Named Routes in Blade

HTML
<a href="{{ route('shops.show', $shop->id) }}">{{ $shop->name }}</a>

<form action="{{ route('shops.update', $shop->id) }}" method="POST">
    @method('PUT')
    @csrf
    <!-- form fields -->
</form>

Output:

TEXT
// Execution Successful

7. API Routing

routes/api.php Used exclusively for API routing; automatically adds the /api prefix.

(1) apiResource Route

PHP
// routes/api.php
use App\Http\Controllers\Api\ShopController;

Route::apiResource('shops', ShopController::class);
// Generates:
// GET    /api/shops        → index
// POST   /api/shops        → store
// GET    /api/shops/{shop} → show
// PUT    /api/shops/{shop} → update
// DELETE /api/shops/{shop} → destroy
Method apiResource resource
index
create
store
show
edit
update
destroy

(2) API Version Control

PHP
Route::prefix('v1')->group(function () {
    Route::apiResource('shops', Api\V1\ShopController::class);
    Route::apiResource('orders', Api\V1\OrderController::class);
});

Route::prefix('v2')->group(function () {
    Route::apiResource('shops', Api\V2\ShopController::class);
});

(1) ▶ Example: ShopMetrics API Routing Blueprint

PHP
// routes/api.php
Route::middleware('auth:sanctum')->group(function () {
    Route::prefix('v1')->name('api.v1.')->group(function () {
        Route::apiResource('tenants.shops', Api\V1\TenantShopController::class);
        Route::apiResource('shops.orders', Api\V1\ShopOrderController::class);
        Route::apiResource('products', Api\V1\ProductController::class);
        Route::get('analytics/overview', [Api\V1\AnalyticsController::class, 'overview']);
        Route::post('reports/generate', [Api\V1\ReportController::class, 'generate']);
    });
});

Output:

TEXT
// Execution Successful

8. Route Matching Process

100%
flowchart LR
    A[HTTP Request] --> B{Match Route?}
    B -->|Yes| C[Extract Parameters]
    C --> D[Run Middleware]
    D --> E[Call Controller Method]
    E --> F[Return Response]
    B -->|No| G[Fallback Route]
    G --> H[404 Not Found]

9. Comprehensive Example: ShopMetrics Complete Routing Blueprint

PHP
// ============================================
// Comprehensive: ShopMetrics complete routes
// Covers: web routes, api routes, groups, constraints
// ============================================

// routes/web.php
Route::get('/', [HomeController::class, 'index'])->name('home');
Route::get('/pricing', [PricingController::class, 'index'])->name('pricing');

Route::middleware('auth')->group(function () {
    Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
    Route::resource('shops', ShopController::class)->whereNumber('shop');
    Route::resource('shops.orders', OrderController::class)->shallow();
    Route::post('/shops/{shop}/logo', [ShopLogoController::class, 'update'])
        ->name('shops.logo.update');
});

// routes/api.php
Route::prefix('v1')->middleware('auth:sanctum')->group(function () {
    Route::apiResource('shops', Api\ShopController::class);
    Route::apiResource('shops.products', Api\ProductController::class)->shallow();
    Route::apiResource('shops.orders', Api\OrderController::class)->shallow();
    Route::get('analytics/summary', [Api\AnalyticsController::class, 'summary']);
    Route::post('reports/generate', [Api\ReportController::class, 'generate']);
});

❓ FAQ

Q What is the difference between routes/web.php and routes/api.php?
A Routes in web.php automatically apply the web middleware group (Session, CSRF, cookie encryption), making it suitable for page requests; routes in api.php automatically apply the API middleware group (throttle rate limiting), and URLs are automatically prefixed with /api, making it suitable for API requests.
Q When should I use Route::resource, and when should I define routes manually?
A RESTful CRUD operations can be handled with a single line using resource/apiResource; for non-standard operations (such as search, export, and bulk operations), define additional routes manually.
Q What are the benefits of naming routes?
A Naming routes decouples URLs from the code. To modify a URL, you only need to change the route definition, and all route() calls are automatically updated. With hard-coded URLs, you have to perform a global search-and-replace whenever you make a change, which makes it easy to miss some instances.
Q What is a shallow route?
A By default, nested resources generate URLs like /shops/{shop}/orders/{order}. The "shallow" option ensures that sub-resources are nested only when an ID is required: show, edit, update, and delete use /orders/{order}, while index and create retain the nested structure. This reduces the URL depth.
Q Does having too many routes affect performance?
A The number of routes has very little impact on performance, as Laravel uses an efficient matching algorithm. However, if you have more than 1,000 routes, we recommend caching the route table using php artisan route:cache.
Q How do I view all registered routes?
A Run php artisan route:list to list all routes, including the method, URI, name, and middleware. Add --path=shops to filter routes by a specific prefix.

📖 Summary


📝 Exercises

  1. Basic Exercise (⭐): Define the following routes for ShopMetrics: Home page (GET /), About page (GET /about), and Contact page (GET+POST /contact). Use named routes and verify that they are accessible in a browser.

  2. Advanced Exercise (⭐⭐): Use route groups to design an API v1 route blueprint for ShopMetrics, including three apiResources—shops, products, and orders—along with authentication middleware and the /api/v1 prefix.

  3. Challenge (⭐⭐⭐): Implement multi-tenant route grouping /{tenant}/*. Write a TenantResolve middleware to parse the tenant from the URL and inject it into the Request, ensuring that all sub-routes can retrieve the current tenant via $request->tenant().

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏