> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ooneex.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Middleware

> Intercept HTTP and WebSocket requests in a decorator-registered pipeline before they reach a controller.

The `@ooneex/middleware` component is a pipeline framework for intercepting requests. Each middleware implements the `IMiddleware` interface (or `ISocketMiddleware` for WebSockets), receives the request `context`, and returns it — modified or unchanged — to the next stage. Register a class with `@decorator.middleware()` and the container resolves it; the app runs registered middleware in order before the controller handles the request.

## Why this component

* **One interface.** Every HTTP middleware implements `IMiddleware` with a single `handler(context)` method — predictable to write, read, and test.
* **Context in, context out.** The same `context` object flows through every stage, carrying the request, response, and headers; you read and mutate it in place.
* **Short-circuiting.** Write a response (`context.response.json(...)`, `context.response.exception(...)`) to halt the pipeline before the controller — for auth, rate limits.
* **WebSocket support.** `ISocketMiddleware` mirrors the HTTP shape against the socket context for connection-time interception.
* **Container-managed.** Decorate a class and resolve it through dependency injection — constructor-inject env, loggers, or services.

## How it works

The app holds an ordered list of middleware. For each incoming request it builds a `context` and passes it through every registered middleware in sequence, then to the matched controller. Each `handler` returns the context to continue the chain.

| Stage                 | What happens                                                                                                                                                                |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Before the controller | Each middleware's `handler` runs in registration order, reading and mutating the shared `context`.                                                                          |
| Short-circuit         | If a middleware writes a response (e.g. `context.response.exception(...)` or `context.response.json(...)`), the pipeline can resolve early without reaching the controller. |
| At the controller     | The fully processed `context` (with any state a middleware attached, like a resolved user) reaches the route handler.                                                       |

A middleware is "before" by doing its work at the top of `handler` and then returning `context`. Because the same context object carries the response, middleware can also shape the outgoing response (set headers, status) before returning. The contract is simple: **always return the context** so the chain continues.

```typescript theme={null}
public async handler(context: ContextType): Promise<ContextType> {
  // Pre-processing: inspect/modify request, attach state, set response headers
  return context; // hand off to the next middleware or the controller
}
```

## Decorator and usage

### `@decorator.middleware()`

Registers a class as middleware with the dependency injection container. It accepts an optional scope (defaults to singleton). The class must implement `IMiddleware` (HTTP) or `ISocketMiddleware` (WebSocket).

```typescript theme={null}
interface IMiddleware<T extends ContextConfigType = ContextConfigType> {
  handler: (context: ContextType<T>) => Promise<ContextType<T>> | ContextType<T>;
}
```

A real HTTP middleware reads the context, optionally writes to the response to short-circuit, and returns the context:

```typescript theme={null}
import type { ContextType } from "@ooneex/controller";
import { decorator, type IMiddleware } from "@ooneex/middleware";

@decorator.middleware()
export class AuthMiddleware implements IMiddleware {
  public async handler(context: ContextType): Promise<ContextType> {
    const authHeader = context.header.get("Authorization");

    if (!authHeader?.startsWith("Bearer ")) {
      // Short-circuit: write a response and the controller is skipped
      context.response.exception("Missing authorization header", { status: 401 });
      return context;
    }

    // Continue to the next middleware / controller
    return context;
  }
}
```

Inject dependencies through the constructor — the container provides them when it resolves the middleware:

```typescript theme={null}
import { AppEnv } from "@ooneex/app-env";
import { inject } from "@ooneex/container";
import type { ContextType } from "@ooneex/controller";
import { decorator, type IMiddleware } from "@ooneex/middleware";

@decorator.middleware()
export class VersionMiddleware implements IMiddleware {
  constructor(@inject(AppEnv) private readonly env: AppEnv) {}

  public async handler(context: ContextType): Promise<ContextType> {
    context.response.header.set("X-App-Version", this.env.APP_VERSION ?? "unknown");
    return context;
  }
}
```

WebSocket middleware uses the same decorator and shape against the socket context via `ISocketMiddleware`:

```typescript theme={null}
import type { ContextType } from "@ooneex/socket";
import { decorator, type ISocketMiddleware } from "@ooneex/middleware";

@decorator.middleware()
export class SocketAuthMiddleware implements ISocketMiddleware {
  public async handler(context: ContextType): Promise<ContextType> {
    return context;
  }
}
```

## Best practices

* **Always return the context.** The chain continues only when `handler` returns the context object; never return a new object in its place.
* **Mutate in place.** Read from and write to the shared `context` — attach resolved state (like a user) for downstream middleware and the controller to use.
* **Short-circuit deliberately.** Write a response only when you mean to stop the pipeline (auth failures, rate limits); otherwise fall through.
* **Keep middleware focused.** One concern per class — auth, logging, rate limiting — so the registration order reads as a clear pipeline.
* **Mind the order.** Middleware runs in registration order; put cross-cutting concerns (logging, headers) before guards that may short-circuit.
* **Inject, don't reach.** Pull env, loggers, and services through the constructor with `@inject` rather than constructing them inside `handler`.

## CLI command

Scaffold a middleware class and its test file with the generator. It writes the class under `modules/<module>/src/middlewares/<Name>Middleware.ts`, adds a matching test, and installs `@ooneex/middleware` if it is missing.

```bash theme={null}
# Interactive: prompts for the name and whether it is a socket middleware
ooneex middleware:create

# Provide the name
ooneex middleware:create --name=Auth

# Socket middleware in a specific module, overwriting an existing file
ooneex middleware:create --name=Auth --module=auth --is-socket=true --override
```

| Option        | Description                                                               | Default             |
| ------------- | ------------------------------------------------------------------------- | ------------------- |
| `--name`      | Middleware class name. The `Middleware` suffix is appended automatically. | Prompted if omitted |
| `--module`    | Target module the class is generated into.                                | `shared`            |
| `--is-socket` | Generate a WebSocket middleware against the socket context.               | Prompted if omitted |
| `--override`  | Overwrite an existing class without prompting.                            | `false`             |

The generated class is a ready-to-implement `IMiddleware` stub:

```typescript theme={null}
import type { ContextType } from "@ooneex/controller";
import { decorator, type IMiddleware } from "@ooneex/middleware";

@decorator.middleware()
export class AuthMiddleware implements IMiddleware {
  public async handler(context: ContextType): Promise<ContextType> {
    // Example: Add custom header
    // context.response.header("X-Custom-Header", "value");

    return context
  }
}
```

A socket middleware stub is identical except it imports `ContextType` from `@ooneex/socket`. After generating, register the class in the `middlewares` array of your module.

See [middleware:create](/cli/commands/middleware-create) for the full command reference.

## Use with Claude and Codex

The generator ships a matching `middleware:create` skill. It runs the scaffold and then guides your AI agent through completing the middleware — implementing `handler` with real logic (auth checks, logging, header injection), wiring dependencies through the constructor, and registering the class in its module. Initialize the skills once for your agent:

<Tabs>
  <Tab title="Claude">
    ```bash theme={null}
    ooneex claude:init
    ```

    Then ask Claude in natural language — it maps the request to the generator, runs it, and fills in the implementation:

    ```text Prompt icon="terminal" wrap theme={null}
    Create a middleware that logs every incoming request.
    ```
  </Tab>

  <Tab title="Codex">
    ```bash theme={null}
    ooneex codex:init
    ```

    Then ask Codex in natural language — it maps the request to the generator, runs it, and fills in the implementation:

    ```text Prompt icon="terminal" wrap theme={null}
    Create a middleware that logs every incoming request.
    ```
  </Tab>
</Tabs>

For example, the prompt above maps to `middleware:create --name=Logging`, then implements `handler` to log the request method and path before returning the context.
