Laravel Request Lifecycle

Understand the journey of an HTTP request through Laravel

Understanding the request lifecycle is crucial for debugging, optimization, and building middleware.

The Journey of a Request:
1. Entry Point (public/index.php) - Request enters here
2. Autoloader - Composer autoloads classes
3. Bootstrap - Application is created (bootstrap/app.php)
4. HTTP Kernel - Request is captured and sent through middleware
5. Router - Finds matching route
6. Middleware - Route-specific middleware runs
7. Controller - Action is executed
8. Response - Generated and sent back through middleware
9. Termination - Application sends response to browser

Why This Matters:
• Middleware order affects request handling
• Understanding this helps debug issues
• Know when database connections are made
• Optimize performance at the right stage

Real-World Example:
If your API is slow, knowing the lifecycle helps you identify whether it's middleware (authentication), the controller (business logic), or database queries causing the delay.

Code Examples

Step 1-3: Entry Point & Bootstrap
💡 Solution php
<?php
// public/index.php - The entry point
define('LARAVEL_START', microtime(true));

// Step 1: Register Composer autoloader
require __DIR__.'/../vendor/autoload.php';

// Step 2: Bootstrap the application
$app = require_once __DIR__.'/../bootstrap/app.php';

// Step 3: Create HTTP Kernel and handle request
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

// Send response to browser
$response->send();

// Perform termination tasks (logging, cleanup)
$kernel->terminate($request, $response);

// This is what happens when you visit your Laravel app!
// Every request goes through this exact flow.

💡 The index.php file is the single entry point for all requests. It bootstraps Laravel and creates the HTTP Kernel to handle the request.

Step 4-5: HTTP Kernel & Middleware Pipeline
💡 Solution php
<?php
// app/Http/Kernel.php
class Kernel extends HttpKernel
{
    // Global middleware (runs on EVERY request)
    protected $middleware = [
        \App\Http\Middleware\TrustProxies::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    ];
    
    // Middleware groups
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
        ],
        
        'api' => [
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];
}

// Request flows through middleware like this:
// Request → TrustProxies → ValidatePostSize → TrimStrings 
// → EncryptCookies → StartSession → VerifyCsrfToken 
// → YOUR CONTROLLER 
// → VerifyCsrfToken → StartSession → EncryptCookies (back)
// → Response

// Think of it as an onion - request goes IN, response goes OUT

💡 Global middleware runs on every request. Middleware wraps your controller like layers of an onion - the request goes through each layer in order, then the response comes back through them in reverse.

Step 6-7: Router & Controller Execution
💡 Solution php
<?php
// routes/web.php
Route::get('/orders/{id}', [OrderController::class, 'show'])
     ->middleware(['auth', 'verified']);

// What happens internally:
// 1. Router matches the URI pattern
// 2. Router checks route-specific middleware (auth, verified)
// 3. Middleware pipeline executes (in addition to global middleware)
// 4. Route model binding occurs (if using implicit binding)
// 5. Controller method is resolved from Service Container
// 6. Dependencies are injected

// OrderController.php
class OrderController extends Controller
{
    // These dependencies are auto-injected!
    public function show(Order $order, OrderRepository $repository)
    {
        // $order is already loaded via route model binding
        // $repository is resolved from Service Container
        
        $order->loadMissing(['items', 'customer']);
        
        return view('orders.show', [
            'order' => $order,
            'related' => $repository->getRelated($order),
        ]);
    }
}

// Timeline at this point:
// 0-50ms:  Middleware execution
// 50-60ms: Route matching
// 60-70ms: Controller resolution
// 70-200ms: Your business logic (database queries, etc.)
// 200ms+:  View rendering

💡 After middleware, the router finds the matching route and executes route-specific middleware. Then it resolves the controller from the container with all dependencies injected.

Step 8-9: Response & Termination
💡 Solution php
<?php
// Controller returns a response
return response()->json([
    'success' => true,
    'order' => $order,
], 200);

// OR returns a view (converted to Response internally)
return view('orders.show', compact('order'));

// Response travels BACK through middleware (in reverse)
// ← Response leaves Controller
// ← ShareErrorsFromSession (adds flash messages to session)
// ← VerifyCsrfToken (no action on response)
// ← StartSession (saves session data)
// ← EncryptCookies (encrypts cookies)
// → Response sent to browser!

// After response is sent, termination callbacks run:
public function terminate($request, $response)
{
    // Log analytics (doesn't slow down response)
    Analytics::track($request);
    
    // Queue cleanup jobs
    Queue::push(new CleanupTempFiles());
    
    // These run AFTER the user receives the response
    // Perfect for slow tasks that don't affect UX
}

// Full lifecycle timing example:
// 0ms:     Request arrives at index.php
// 1ms:     Application bootstrapped
// 5ms:     Global middleware executed
// 10ms:    Route matched
// 15ms:    Route middleware executed
// 20ms:    Controller resolved
// 150ms:   Controller logic + DB queries
// 180ms:   View rendered
// 185ms:   Response through middleware
// 200ms:   Response sent to user ← User sees page!
// 201ms+:  Termination tasks (user doesn't wait)

💡 The response goes back through middleware in reverse order. After sending the response, termination callbacks run for cleanup tasks - the user doesn't wait for these!