Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"@nestjs/swagger": "^11.2.5",
"@nestjs/throttler": "^6.4.0",
"@nestjs/typeorm": "^11.0.0",
"@types/micromatch": "^4.0.10",
"@types/passport-google-oauth20": "^2.0.16",
"@types/pdfkit": "^0.14.0",
"bcryptjs": "^3.0.2",
Expand All @@ -43,6 +44,7 @@
"google-auth-library": "^9.15.1",
"ioredis": "^5.6.1",
"jsonwebtoken": "^9.0.2",
"micromatch": "^4.0.8",
"nodemailer": "^7.0.12",
"oauth2client": "^1.0.0",
"passport": "^0.7.0",
Expand Down
150 changes: 150 additions & 0 deletions backend/src/common/middleware/utils/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Conditional Middleware Utilities

This module provides higher-order middleware wrappers that allow you to conditionally apply middleware based on route patterns.

## Installation

The utilities are exported from `src/index.ts`:

```typescript
import { unless, onlyFor, RoutePattern } from '@/index';
```

## Usage

### `unless(middleware, excludePatterns)`

Skips middleware execution for routes matching the provided patterns.

```typescript
import { unless } from '@/index';
import { CorrelationIdMiddleware } from './correlation-id.middleware';

// Skip correlation ID for health and metrics endpoints
const conditionalMiddleware = unless(
new CorrelationIdMiddleware(),
['/health', '/metrics', '/api/*/health']
);

// Apply in your module
app.use(conditionalMiddleware.use.bind(conditionalMiddleware));
```

### `onlyFor(middleware, includePatterns)`

Executes middleware only for routes matching the provided patterns.

```typescript
import { onlyFor } from '@/index';
import { AuthMiddleware } from './auth.middleware';

// Apply auth middleware only to admin routes
const conditionalMiddleware = onlyFor(
new AuthMiddleware(),
['/api/admin/*', '/admin/**']
);

// Apply in your module
app.use(conditionalMiddleware.use.bind(conditionalMiddleware));
```

## Pattern Types

The utilities support three types of patterns:

### 1. Exact Strings
```typescript
unless(middleware, '/health')
```

### 2. Regular Expressions
```typescript
unless(middleware, /^\/api\/v\d+\/status$/)
```

### 3. Glob Patterns
```typescript
unless(middleware, [
'/api/*/metrics',
'/static/**',
'/admin/**/users/**'
])
```

## Examples

### Skip middleware for static assets
```typescript
const conditionalMiddleware = unless(
new LoggingMiddleware(),
[
'/static/**',
'/assets/**',
'/**/*.css',
'/**/*.js',
'/**/*.png',
'/**/*.jpg'
]
);
```

### Apply middleware only to API routes
```typescript
const conditionalMiddleware = onlyFor(
new RateLimitMiddleware(),
[
'/api/**',
'!/api/docs/**' // Exclude API docs
]
);
```

### Complex routing scenarios
```typescript
// Skip authentication for public routes
const publicRoutes = [
'/health',
'/metrics',
'/auth/login',
'/auth/register',
'/public/**',
'/api/v1/public/**'
];

const conditionalAuth = unless(
new AuthMiddleware(),
publicRoutes
);
```

## Performance

The conditional middleware is designed to have minimal overhead:

- Zero overhead for non-matching routes (early return)
- Efficient pattern matching using micromatch
- Stateless implementation
- No memory leaks

## Error Handling

The utilities gracefully handle:

- Invalid patterns (treated as non-matching)
- Null/undefined patterns (treated as non-matching)
- Malformed regex patterns (fallback to string comparison)
- Empty pattern arrays (treated as non-matching)

## TypeScript Support

Full TypeScript support with proper type definitions:

```typescript
import { RoutePattern } from '@/index';

const patterns: RoutePattern = [
'/api/users', // string
/^\/api\/v\d+/, // regex
'/admin/**' // glob
];
```
Loading
Loading