routing/middleware.md

Middleware

Middleware

Middleware allows application code to run during request processing before the final route handler is executed.

OwnWork uses the middleware facilities provided by Coretex.

Middleware receives the current Request and Response objects together with a continuation callback. It can perform work before continuing, stop the request by returning a result, or continue execution with $next().

Middleware Pipeline

A request with middleware follows this general flow:

Request
   │
   ▼
Global Middleware
   │
   ▼
Route Middleware
   │
   ▼
Route Handler
   │
   ▼
Response

OwnWork builds the middleware chain in app/Http/Kernel.php.

The kernel recursively executes each middleware. When a middleware calls $next(), the next middleware in the chain is executed. When there are no more middleware entries, the route resolver executes the route handler.

Conceptually:

Request
   │
   ▼
Middleware A
   │
   ▼
Middleware B
   │
   ▼
Route Handler
   │
   ▼
Response

Middleware Signature

The middleware generated by OwnWork uses this signature:

public static function handle(
    Request $request,
    Response $response,
    callable $next
) {
    return $next();
}

The three arguments represent:

Argument Purpose
$request Current HTTP request
$response Current HTTP response
$next Continue to the next middleware or route handler

The default middleware template generated by the worker defines handle() as a static method.

Creating Middleware

Use the OwnWork worker:

php worker make middleware AuthMiddleware

The worker creates the file under:

app/Middleware/

For example:

app/Middleware/AuthMiddleware.php

The generated class uses the App\Middleware namespace and contains a static handle() method.

The worker's component generator creates the file from:

resources/template/Middleware.php

Basic Middleware

A generated middleware can simply continue the request:

<?php

declare(strict_types = 1);

namespace App\Middleware;

use Dhruv125\Coretex\Support\Request;
use Dhruv125\Coretex\Support\Response;

class AuthMiddleware
{
    public static function handle(
        Request $request,
        Response $response,
        callable $next
    ) {
        return $next();
    }
}

Calling:

return $next();

passes control to the next middleware.

If there is no next middleware, OwnWork's kernel invokes the route resolver.

Middleware Before the Handler

Code before $next() executes before downstream request processing:

public static function handle(
    Request $request,
    Response $response,
    callable $next
) {
    // Runs before downstream processing.

    return $next();
}

This is useful for request checks, authentication, logging, and other pre-processing operations.

Middleware After the Handler

Code can also run after $next() returns:

public static function handle(
    Request $request,
    Response $response,
    callable $next
) {
    $result = $next();

    // Runs after downstream processing.

    return $result;
}

This creates the usual wrapping behavior:

Middleware A
    │
    ├── Before
    │
    ▼
Middleware B
    │
    ├── Before
    │
    ▼
Route Handler
    │
    └── Return
    │
    ▼
Middleware B
    └── After
    │
    ▼
Middleware A
    └── After

The reverse-order behavior occurs because $next() returns control to the middleware that called it.

Stopping the Pipeline

A middleware does not have to call $next().

It can return a result directly:

public static function handle(
    Request $request,
    Response $response,
    callable $next
) {
    if (!$request->has("token")) {
        return $response->json([
            "message" => "Unauthorized"
        ]);
    }

    return $next();
}

When the middleware returns without calling $next(), the remaining middleware and route handler are not executed through that path.

Global Middleware

Global middleware applies to requests handled by the application.

Register it through the route object:

$route->globalMiddleware(
    [AuthMiddleware::class, "handle"]
);

A closure can also be registered:

$route->globalMiddleware(
    function ($request, $response, $next) {
        return $next();
    }
);

OwnWork's kernel retrieves the registered global middleware with:

$route->getGlobalMiddleware();

It then adds the global middleware to the middleware chain before executing the route-specific middleware.

Global Middleware Parameters

The route API also accepts an optional parameter array when registering global middleware:

$route->globalMiddleware(
    [AuthMiddleware::class, "handle"],
    [
        "role" => "admin"
    ]
);

The parameters are stored as part of the middleware definition.

The middleware implementation is responsible for using any configured parameters.

Route Middleware

Middleware can be associated with an individual route through the router's middleware API:

$route->middleware(
    "GET",
    "/users",
    [AuthMiddleware::class, "handle"]
);

The middleware is associated with the specified HTTP method and route URL.

For example, the route itself can be registered as:

$route->get("/users", [
    UserController::class,
    "index"
]);

and middleware can then be attached to that route:

$route->middleware(
    "GET",
    "/users",
    [AuthMiddleware::class, "handle"]
);

Applying Middleware to Multiple Routes

The middleware API accepts multiple URLs:

$route->middleware(
    "GET",
    [
        "/users",
        "/profile",
        "/settings"
    ],
    [AuthMiddleware::class, "handle"]
);

The middleware is added to each specified route.

HTTP Method Matters

Route middleware registration includes the HTTP method.

For example:

$route->middleware(
    "GET",
    "/users",
    [AuthMiddleware::class, "handle"]
);

A POST route for the same URL is a separate route:

$route->get("/users", [
    UserController::class,
    "index"
]);

$route->post("/users", [
    UserController::class,
    "store"
]);

Therefore, middleware registered for GET /users should not be assumed to apply automatically to POST /users.

Middleware with Dynamic Routes

Middleware can be associated with a route containing dynamic parameters:

$route->get("/users/{id}", [
    UserController::class,
    "show"
]);

$route->middleware(
    "GET",
    "/users/{id}",
    [AuthMiddleware::class, "handle"]
);

The middleware is associated with the route pattern:

/users/{id}

The router resolves the incoming URL and extracts its dynamic parameters before the kernel executes the middleware chain.

Middleware Order

The kernel constructs the final middleware chain from the route middleware and global middleware.

Global middleware is added before the route middleware.

Within the resulting chain, middleware executes in order:

Global Middleware
        ↓
Route Middleware
        ↓
Route Handler

For middleware that calls $next(), the return path travels in reverse:

Global A before
  Route A before
    Controller
  Route A after
Global A after

This allows middleware to wrap downstream processing.

Authentication Example

A simple authentication middleware can check request data before allowing the route to continue:

<?php

namespace App\Middleware;

use Dhruv125\Coretex\Support\Request;
use Dhruv125\Coretex\Support\Response;

class AuthMiddleware
{
    public static function handle(
        Request $request,
        Response $response,
        callable $next
    ) {
        $token = $request->get("token");

        if (!$token) {
            return $response->json([
                "message" => "Unauthorized"
            ]);
        }

        return $next();
    }
}

The exact authentication mechanism is application-specific. OwnWork's middleware system does not provide an authentication system by itself.

Logging Example

Middleware can also wrap request processing for logging:

<?php

namespace App\Middleware;

use Dhruv125\Coretex\Support\Request;
use Dhruv125\Coretex\Support\Response;

class LoggingMiddleware
{
    public static function handle(
        Request $request,
        Response $response,
        callable $next
    ) {
        // Log information about the request.

        $result = $next();

        // Log information about the completed request.

        return $result;
    }
}

This keeps request-related behavior outside individual controllers.

Middleware and Controllers

Middleware is generally appropriate for behavior that surrounds request execution.

For example:

Middleware
├── Authentication
├── Authorization
├── Logging
└── Request checks

Controller
├── Application operation
├── Service calls
└── View/response creation

The exact division remains an application design decision.

Request Attributes Available to Middleware

Before the middleware chain is executed, OwnWork's kernel sets several request attributes:

$this->request->setAttribute(
    'currentRoute',
    $result['currentRoute'] ?? '/'
);

$this->request->setAttribute(
    'routesArray',
    $result['routesArray'] ?? null
);

$this->request->setAttribute(
    'dynamicParams',
    $dynamicParams
);

Therefore middleware can inspect information about the matched route through the request object.

For example:

$currentRoute = $request->getAttribute("currentRoute");

$params = $request->getAttribute("dynamicParams");

This happens before OwnWork starts executing the middleware chain.

How OwnWork Executes Middleware

The kernel recursively processes the middleware array.

Conceptually, its execution is:

runMiddlewares()
      │
      ├── Middleware[0]
      │      │
      │      └── $next()
      │             │
      │             ▼
      ├── Middleware[1]
      │      │
      │      └── $next()
      │             │
      │             ▼
      └── Route Resolver

When the middleware array is exhausted, the kernel calls the route resolver with the matched handler.

This means middleware does not directly invoke controllers. The final dispatcher passes the matched handler to Coretex's RouteResolver.

Middleware in the Request Lifecycle

Middleware sits after route matching and before route handler resolution.

For example:

GET /users/42
      │
      ▼
Route matching
      │
      ▼
Extract dynamic parameters
      │
      ▼
Set request attributes
      │
      ▼
Global middleware
      │
      ▼
Route middleware
      │
      ▼
RouteResolver
      │
      ▼
Controller / View / Closure
      │
      ▼
Response

The OwnWork kernel performs this sequence in app/Http/Kernel.php.

Middleware Checklist

When creating middleware:

  • Put application middleware under app/Middleware/.
  • Use the generated App\Middleware namespace.
  • Provide a static handle() method matching the generated middleware structure.
  • Accept the request, response, and $next continuation.
  • Call $next() when downstream processing should continue.
  • Return a result directly when the request should be terminated.
  • Register application-wide middleware with globalMiddleware().
  • Register route-specific middleware with middleware().
  • Remember that route middleware registration is associated with an HTTP method and route URL.
  • Use request attributes when middleware needs information about the matched route.

application/controllers.md