Using Middleware with Routes ============================ Imagine your application as a factory assembly line. Each product (an HTTP request) must pass through several stations; security checks, quality control, packaging—before it leaves the factory (your controller). In LacePHP those “stations” are called **middleware**. Middleware lets you insert reusable, focused logic before (and even after) your controller code runs. This keeps your controllers simple: they only worry about business logic, not every little check or header you need. Why Middleware Matters ---------------------- - **Clear Responsibilities:** Rather than sprinkling checks and logging throughout your controllers, you group each concern into its own class. - **Consistency:** Every route that needs CORS headers or authentication gets the same logic, so nothing slips through the cracks. - **Reusability:** Write a middleware once and attach it to many routes or route-groups—no copy-and-paste. - **Flexibility:** Turn middleware on or off via configuration (in `lace.json`), or apply it only to specific routes. Built-In Middleware You Can Use -------------------------------- LacePHP already includes several ready-made middleware. Here’s a quick reference: .. list-table:: :header-rows: 1 :widths: 15 20 35 * - **Middleware** - **Class** - **Description** * - CORS - ``CorsKnots::class`` - Adds the headers browsers need for cross-origin requests and handles OPTIONS preflight automatically. * - Debug Logging - ``MagicDebugKnots::class`` - When you append ``?debug=lace`` to your URL, logs each request’s start and end for easy tracing. * - Rate Limiting - ``RateLimitKnots::class`` - Limits how many requests a single IP can make in a time window (default 60 requests per 60 seconds). * - Response Caching - ``ShoeCacheKnots::class`` - Stores GET responses on disk and serves them directly when caching is enabled, speeding up repeat requests. Each of these lives under the PHP namespace `Lacebox\Knots`. You do not need to write them yourself, just attach them to your routes. Attaching Middleware to a Single Route -------------------------------------- To protect or enhance one specific endpoint, you can attach middleware in your route definition. For example, to combine CORS and rate-limiting on a `/api/data` route: .. code-block:: php use Lacebox\Knots\CorsKnots; use Lacebox\Knots\RateLimitKnots; use Weave\Middlewares\ExampleMiddleware; use Weave\Controllers\DataController; $router->addRoute( 'GET', # HTTP method '/api/data', # path [DataController::class, 'index'],[ # controller + method CorsKnots::class, # new CorsKnots() [RateLimitKnots::class, [100, 60]], # new RateLimitKnots(100, 60) ExampleMiddleware::class # your own custom middleware ] ); **Step-by-step what happens**: 1. **CORS headers** are sent (so browsers can call this API from other domains). 2. **Rate limit** of 100 requests per 60 seconds is enforced—extra requests return HTTP 429. 3. **ExampleMiddleware** runs (perhaps checking an API key or logging). 4. Finally, **DataController::index()** is called to handle the request. Grouping Multiple Routes ------------------------ Often many routes share the same requirements. Instead of repeating the middleware list, you group them: .. code-block:: php use Lacebox\Knots\MagicDebugKnots; use Lacebox\Knots\ShoeCacheKnots; $router->group( [ # group options 'prefix' => '/reports', # all routes start with /reports ], function($r) { $r->sewGet('/sales', ['ReportController', 'sales']); $r->sewPost('/inventory',['ReportController', 'inventory']); } )->middleware([ MagicDebugKnots::class, # log debug info if ?debug=lace ShoeCacheKnots::class, # cache GET responses ]); Here both `/reports/sales` and `/reports/inventory`: - Log start/end markers when `?debug=lace` is present - Serve cached JSON if available You can still attach extra middleware to individual routes inside the group: .. code-block:: php $router->group( ['prefix' => '/admin', 'namespace' => 'Controllers\Admin'], function($r) { $r->get('/dashboard', ['AdminController', 'index']); $r->post( '/users', ['UserController', 'store'], ['SomeOtherMiddleware::class'] # only for /admin/users ); } ); In this example: - The **group** middleware (perhaps authentication) applies to every `/admin/*` route. - **`SomeOtherMiddleware`** runs only for the `/admin/users` POST request, letting you layer extra checks or features on top. Best Practice Checklist ----------------------- - Give each middleware **one clear job** (e.g. `AuthKnots`, `ThrottleKnots`, `CorsKnots`). - **Order matters**: place security checks first, rate-limits next, then logging or caching. - Use **constructor arguments** when your middleware needs settings (e.g. `new RateLimitKnots(50,30)`). - Keep middleware **lightweight**—delegate heavy work to services or your controllers. Common Pitfalls & Cautions -------------------------- .. warning:: - **Remember to stop** the request if you block it: echo or return a response and call `exit`. - **Avoid raw** calls to `header()` or `echo` after middleware chaining; use `kickback()` to manage HTTPS response codes and headers. - **Check the HTTP method** inside your middleware when you only want it to run on GET or POST. By organising cross-cutting logic into middleware and attaching it clearly to your routes, you ensure your LacePHP app is both secure and maintainable—exactly what a junior developer needs to build confidence and clarity.