# Lockness Middleware
Class-based middleware with dependency injection.
## Create Middleware
```bash
deno task cli make:middleware LogRequest
```
Creates: `src/middleware/log_request_middleware.ts`
## Basic Middleware
```typescript
import { type Context, type Next } from '@lockness/core'
export class LogRequestMiddleware {
async handle(c: Context, next: Next) {
console.log(`${c.req.method} ${c.req.path}`)
await next()
}
}
```
## Middleware with DI
```typescript
import { Service, Inject, type Context, type Next } from '@lockness/core'
import { Logger } from '@service/logger.ts'
@Service()
export class LogRequestMiddleware {
@Inject(Logger)
accessor logger!: Logger
async handle(c: Context, next: Next) {
this.logger.info(`${c.req.method} ${c.req.path}`)
await next()
}
}
```
## Apply Middleware
### Global Middleware (All Routes)
```typescript
// src/kernel.tsx
import { Kernel } from '@lockness/core'
import { LogRequestMiddleware } from '@middleware/log_request_middleware.ts'
import { AuthMiddleware } from '@middleware/auth_middleware.ts'
export const kernel = new Kernel()
kernel.use(LogRequestMiddleware)
kernel.use(AuthMiddleware)
```
### Controller Middleware (All Methods)
```typescript
import { Controller, Middleware, Get } from '@lockness/core'
import { AuthMiddleware } from '@middleware/auth_middleware.ts'
@Controller('/admin')
@Middleware(AuthMiddleware)
export class AdminController {
@Get('/dashboard')
dashboard(c: Context) {
return c.html()
}
@Get('/users')
users(c: Context) {
return c.html()
}
}
```
### Route Middleware (Single Method)
```typescript
import { Controller, Middleware, Get, Post } from '@lockness/core'
import { RateLimitMiddleware } from '@middleware/rate_limit_middleware.ts'
@Controller('/api')
export class ApiController {
@Get('/data')
getData(c: Context) {
return c.json({ data: [] })
}
@Post('/submit')
@Middleware(RateLimitMiddleware)
submit(c: Context) {
return c.json({ success: true })
}
}
```
## Response Modification
```typescript
export class AddHeaderMiddleware {
async handle(c: Context, next: Next) {
await next()
c.header('X-Custom-Header', 'value')
}
}
```
## Request Termination
```typescript
export class CheckMaintenanceMiddleware {
async handle(c: Context, next: Next) {
if (Deno.env.get('MAINTENANCE_MODE') === 'true') {
return c.text('Under maintenance', 503)
}
await next()
}
}
```
## Execution Order
Middleware executes in the order it's registered:
```typescript
// src/kernel.tsx
kernel.use(CorsMiddleware) // 1st
kernel.use(LogRequestMiddleware) // 2nd
kernel.use(AuthMiddleware) // 3rd
@Controller('/api')
@Middleware(RateLimitMiddleware) // 4th
export class ApiController {
@Post('/submit')
@Middleware(ValidationMiddleware) // 5th
submit(c: Context) {
// Handler runs last
}
}
```
## Common Middleware Examples
### CORS
```typescript
export class CorsMiddleware {
async handle(c: Context, next: Next) {
c.header('Access-Control-Allow-Origin', '*')
c.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE')
c.header('Access-Control-Allow-Headers', 'Content-Type')
if (c.req.method === 'OPTIONS') {
return c.text('', 204)
}
await next()
}
}
```
### Rate Limiting
```typescript
import { Service, Inject } from '@lockness/core'
import { Cache } from '@lockness/cache'
@Service()
export class RateLimitMiddleware {
@Inject(Cache)
accessor cache!: Cache
async handle(c: Context, next: Next) {
const ip = c.req.header('x-forwarded-for') || 'unknown'
const key = `rate_limit:${ip}`
const count = await this.cache.get(key) || 0
if (count >= 100) {
return c.text('Too many requests', 429)
}
await this.cache.set(key, count + 1, 60) // 60 seconds
await next()
}
}
```
### Authentication Check
```typescript
import { Service, type Context, type Next, auth, session } from '@lockness/core'
@Service()
export class AuthMiddleware {
async handle(c: Context, next: Next) {
if (!auth(c).check()) {
session(c).flash('error', 'Please log in')
return c.redirect('/auth/login')
}
await next()
}
}
```
### Request Timing
```typescript
@Service()
export class TimingMiddleware {
@Inject(Logger)
accessor logger!: Logger
async handle(c: Context, next: Next) {
const start = Date.now()
await next()
const duration = Date.now() - start
this.logger.info(`${c.req.method} ${c.req.path} - ${duration}ms`)
}
}
```
## Best Practices
- Keep middleware focused on single responsibility
- Use DI for dependencies (services, repositories)
- Apply middleware at appropriate scope (global/controller/route)
- Order matters - place auth before rate limiting
- Use early returns to terminate request flow
- Modify response after `await next()` if needed
- Use `@Service()` when middleware needs DI