or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

auth.mdbase-controller.mddecorators.mdindex.mdmiddleware.mdresults.mdserver.md
tile.json

middleware.mddocs/

0

# Middleware System

1

2

Middleware integration system supporting both Express middleware and custom Inversify-based middleware with dependency injection support. The system allows for flexible middleware composition at both controller and method levels.

3

4

## Capabilities

5

6

### Base Middleware Class

7

8

Abstract base class for creating custom middleware that integrates with Inversify dependency injection.

9

10

```typescript { .api }

11

/**

12

* Abstract base class for middleware with dependency injection support

13

*/

14

abstract class BaseMiddleware {

15

/** HTTP context initialized when middleware is invoked */

16

httpContext: HttpContext;

17

18

/**

19

* Binds a service to the request-scoped container

20

* @param serviceIdentifier - Service identifier to bind

21

* @returns Binding syntax for fluent configuration

22

*/

23

protected bind<T>(

24

serviceIdentifier: interfaces.ServiceIdentifier<T>

25

): interfaces.BindingToSyntax<T>;

26

27

/**

28

* Abstract handler method that must be implemented by concrete middleware

29

* @param req - Express request object

30

* @param res - Express response object

31

* @param next - Express next function

32

*/

33

abstract handler(

34

req: Request,

35

res: Response,

36

next: NextFunction

37

): void | Promise<void>;

38

}

39

```

40

41

### Middleware Decorator

42

43

Decorator for applying middleware to controllers or individual methods.

44

45

```typescript { .api }

46

/**

47

* Applies middleware to a controller class or method

48

* @param middleware - Middleware functions or service identifiers to apply

49

* @returns Decorator function for classes or methods

50

*/

51

function withMiddleware(...middleware: Middleware[]): ClassDecorator | MethodDecorator;

52

```

53

54

### Middleware Types

55

56

Type definitions for middleware integration.

57

58

```typescript { .api }

59

/**

60

* Middleware type supporting both Express handlers and Inversify service identifiers

61

*/

62

type Middleware = interfaces.ServiceIdentifier | RequestHandler;

63

64

/**

65

* Middleware metadata interface for storing middleware configuration

66

*/

67

interface MiddlewareMetaData {

68

[identifier: string]: Middleware[];

69

}

70

```

71

72

**Usage Examples:**

73

74

```typescript

75

import { injectable } from "inversify";

76

import {

77

BaseMiddleware,

78

withMiddleware,

79

controller,

80

httpGet,

81

BaseHttpController

82

} from "inversify-express-utils";

83

84

// Custom Middleware with Dependency Injection

85

@injectable()

86

class LoggingMiddleware extends BaseMiddleware {

87

async handler(req: Request, res: Response, next: NextFunction): Promise<void> {

88

const startTime = Date.now();

89

90

// Access injected services through HTTP context

91

const logger = this.httpContext.container.get<Logger>("Logger");

92

93

logger.info(`${req.method} ${req.path} - Request started`);

94

95

// Continue to next middleware/handler

96

next();

97

98

// Log completion (this runs after the response)

99

res.on("finish", () => {

100

const duration = Date.now() - startTime;

101

logger.info(`${req.method} ${req.path} - Completed in ${duration}ms`);

102

});

103

}

104

}

105

106

@injectable()

107

class AuthenticationMiddleware extends BaseMiddleware {

108

async handler(req: Request, res: Response, next: NextFunction): Promise<void> {

109

const token = req.headers.authorization;

110

111

if (!token) {

112

res.status(401).json({ error: "Authentication required" });

113

return;

114

}

115

116

try {

117

// Use services from container

118

const authService = this.httpContext.container.get<AuthService>("AuthService");

119

const user = await authService.validateToken(token);

120

121

// Store user in request for later use

122

(req as any).user = user;

123

next();

124

} catch (error) {

125

res.status(401).json({ error: "Invalid token" });

126

}

127

}

128

}

129

130

@injectable()

131

class RateLimitMiddleware extends BaseMiddleware {

132

async handler(req: Request, res: Response, next: NextFunction): Promise<void> {

133

const cacheService = this.httpContext.container.get<CacheService>("CacheService");

134

const clientIp = req.ip;

135

const key = `rate_limit_${clientIp}`;

136

137

const requestCount = await cacheService.increment(key, 60); // 60 second window

138

139

if (requestCount > 100) { // 100 requests per minute

140

res.status(429).json({ error: "Rate limit exceeded" });

141

return;

142

}

143

144

next();

145

}

146

}

147

148

// Express Middleware Functions

149

function corsMiddleware(req: Request, res: Response, next: NextFunction) {

150

res.header("Access-Control-Allow-Origin", "*");

151

res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");

152

res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");

153

154

if (req.method === "OPTIONS") {

155

res.sendStatus(204);

156

return;

157

}

158

159

next();

160

}

161

162

function compressionMiddleware(req: Request, res: Response, next: NextFunction) {

163

// Simple compression logic

164

const originalSend = res.send;

165

res.send = function(body) {

166

if (typeof body === "string" && body.length > 1000) {

167

res.header("Content-Encoding", "gzip");

168

// Compress body (pseudo-code)

169

body = compress(body);

170

}

171

return originalSend.call(this, body);

172

};

173

next();

174

}

175

```

176

177

### Controller-Level Middleware

178

179

Apply middleware to all methods in a controller.

180

181

```typescript { .api }

182

// Using decorator syntax

183

@controller("/api/users")

184

@withMiddleware(LoggingMiddleware, AuthenticationMiddleware)

185

class UserController extends BaseHttpController {

186

// All methods inherit the middleware

187

188

@httpGet("/")

189

getUsers() {

190

return this.ok(["user1", "user2"]);

191

}

192

193

@httpPost("/")

194

createUser(@requestBody() userData: any) {

195

return this.created("/users/123", userData);

196

}

197

}

198

199

// Using constructor parameter

200

@controller("/api/products", LoggingMiddleware, corsMiddleware)

201

class ProductController extends BaseHttpController {

202

@httpGet("/")

203

getProducts() {

204

return this.ok(["product1", "product2"]);

205

}

206

}

207

```

208

209

### Method-Level Middleware

210

211

Apply middleware to specific methods within a controller.

212

213

```typescript { .api }

214

@controller("/api/admin")

215

class AdminController extends BaseHttpController {

216

@httpGet("/users")

217

@withMiddleware(AuthenticationMiddleware, RateLimitMiddleware)

218

getUsers() {

219

return this.ok(["user1", "user2"]);

220

}

221

222

@httpPost("/users")

223

@withMiddleware(AuthenticationMiddleware, compressionMiddleware)

224

createUser(@requestBody() userData: any) {

225

return this.created("/users/123", userData);

226

}

227

228

// No additional middleware on this method

229

@httpGet("/health")

230

getHealth() {

231

return this.ok({ status: "healthy" });

232

}

233

}

234

```

235

236

### Mixed Middleware Types

237

238

Combine Inversify middleware and Express middleware in the same application.

239

240

```typescript { .api }

241

@controller("/api/files")

242

@withMiddleware(corsMiddleware, LoggingMiddleware) // Express + Inversify middleware

243

class FileController extends BaseHttpController {

244

@httpPost("/upload")

245

@withMiddleware(AuthenticationMiddleware, compressionMiddleware)

246

uploadFile(@requestBody() fileData: any) {

247

return this.created("/files/123", fileData);

248

}

249

250

@httpGet("/:id")

251

@withMiddleware(RateLimitMiddleware)

252

getFile(@requestParam("id") id: string) {

253

return this.ok({ id, name: "file.txt" });

254

}

255

}

256

```

257

258

### Middleware Registration

259

260

Register custom middleware with the Inversify container.

261

262

**Usage Examples:**

263

264

```typescript

265

import { Container } from "inversify";

266

267

const container = new Container();

268

269

// Register middleware classes

270

container.bind<LoggingMiddleware>("LoggingMiddleware").to(LoggingMiddleware);

271

container.bind<AuthenticationMiddleware>("AuthenticationMiddleware").to(AuthenticationMiddleware);

272

container.bind<RateLimitMiddleware>("RateLimitMiddleware").to(RateLimitMiddleware);

273

274

// Register services that middleware depends on

275

container.bind<Logger>("Logger").to(ConsoleLogger);

276

container.bind<AuthService>("AuthService").to(JwtAuthService);

277

container.bind<CacheService>("CacheService").to(RedisCache);

278

279

// Create server with container

280

const server = new InversifyExpressServer(container);

281

282

// Configure global Express middleware

283

server.setConfig((app) => {

284

app.use(express.json());

285

app.use(express.urlencoded({ extended: true }));

286

// Note: Controller/method-specific middleware is handled automatically

287

});

288

```

289

290

### Middleware Execution Order

291

292

Middleware executes in the following order:

293

294

1. **Global app-level middleware** (configured via `setConfig()`)

295

2. **Controller-level middleware** (applied via `@controller()` or `@withMiddleware()`)

296

3. **Method-level middleware** (applied via method decorators)

297

4. **Route handler** (the actual controller method)

298

5. **Error middleware** (configured via `setErrorConfig()`)

299

300

**Usage Examples:**

301

302

```typescript

303

@controller("/api/data", corsMiddleware, LoggingMiddleware) // Middleware 2 & 3

304

class DataController extends BaseHttpController {

305

@httpGet("/")

306

@withMiddleware(AuthenticationMiddleware, RateLimitMiddleware) // Middleware 4 & 5

307

getData() { // Handler executes 6th

308

return this.ok({ data: "sample" });

309

}

310

}

311

312

// Execution order for GET /api/data:

313

// 1. Global middleware (express.json, etc.)

314

// 2. corsMiddleware

315

// 3. LoggingMiddleware

316

// 4. AuthenticationMiddleware

317

// 5. RateLimitMiddleware

318

// 6. getData() method

319

// 7. Error middleware (if any errors occur)

320

```

321

322

### Utility Functions

323

324

Utility functions for working with middleware metadata.

325

326

```typescript { .api }

327

/**

328

* Gets middleware metadata for a specific constructor and key

329

* @param constructor - Target constructor

330

* @param key - Metadata key

331

* @returns Array of middleware for the specified key

332

*/

333

function getMiddlewareMetadata(

334

constructor: DecoratorTarget,

335

key: string

336

): Middleware[];

337

```