or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# Middy Core

1

2

Middy Core is the stylish Node.js middleware engine for AWS Lambda. It provides a fluent, plugin-based architecture that enables developers to create composable and reusable middleware patterns for serverless applications. The core package handles before, after, and error middleware execution, supports both traditional and streaming response patterns, includes built-in timeout handling, and provides a clean API for creating maintainable Lambda functions.

3

4

## Package Information

5

6

- **Package Name**: @middy/core

7

- **Package Type**: npm

8

- **Language**: JavaScript (ES Module)

9

- **Installation**: `npm install @middy/core`

10

- **Node.js**: >=20

11

- **Types**: Full TypeScript support included

12

13

## Core Imports

14

15

```javascript

16

import middy from "@middy/core";

17

```

18

19

For CommonJS (also supported):

20

21

```javascript

22

const middy = require("@middy/core");

23

```

24

25

## Basic Usage

26

27

```javascript

28

import middy from "@middy/core";

29

30

// Basic Lambda handler

31

const lambdaHandler = async (event, context) => {

32

return { statusCode: 200, body: "Hello World" };

33

};

34

35

// Create middlewared handler

36

const handler = middy(lambdaHandler)

37

.use(someMiddleware())

38

.before(async (request) => {

39

console.log("Before handler", request.event);

40

})

41

.after(async (request) => {

42

console.log("After handler", request.response);

43

})

44

.onError(async (request) => {

45

console.log("Error occurred", request.error);

46

});

47

48

export { handler };

49

```

50

51

## Architecture

52

53

Middy Core is built around several key components:

54

55

- **Factory Function**: The main `middy()` function creates middlewared Lambda handlers

56

- **Middleware Chain**: Before, after, and error middleware executed in sequence

57

- **Request Object**: Shared state object passed through the middleware chain

58

- **Plugin System**: Lifecycle hooks for extending functionality and performance monitoring

59

- **Streaming Support**: Native AWS Lambda streaming response support

60

- **Timeout Handling**: Early timeout detection with configurable responses

61

- **Abort Signals**: Built-in AbortSignal support for cancellation

62

63

## Capabilities

64

65

### Factory Function

66

67

Creates a middlewared Lambda handler with fluent API for attaching middleware.

68

69

```typescript { .api }

70

/**

71

* Middy factory function. Use it to wrap your existing handler to enable middlewares on it.

72

* @param handler - Your original AWS Lambda function or PluginObject

73

* @param plugin - Plugin configuration for lifecycle hooks

74

* @returns MiddyfiedHandler with middleware methods

75

*/

76

function middy<TEvent = unknown, TResult = any, TErr = Error, TContext extends LambdaContext = LambdaContext, TInternal extends Record<string, unknown> = {}>(

77

handler?: LambdaHandler<TEvent, TResult> | MiddlewareHandler<LambdaHandler<TEvent, TResult>, TContext, TResult, TEvent> | PluginObject,

78

plugin?: PluginObject

79

): MiddyfiedHandler<TEvent, TResult, TErr, TContext, TInternal>;

80

```

81

82

### Middlewared Handler Interface

83

84

The enhanced Lambda handler returned by `middy()` with middleware attachment methods. It extends both `MiddyInputHandler` and `MiddyInputPromiseHandler` to support both callback and Promise-based execution patterns.

85

86

```typescript { .api }

87

interface MiddyfiedHandler<TEvent = any, TResult = any, TErr = Error, TContext extends LambdaContext = LambdaContext, TInternal extends Record<string, unknown> = {}> extends MiddyInputHandler<TEvent, TResult, TContext>, MiddyInputPromiseHandler<TEvent, TResult, TContext> {

88

/** Attach middleware objects or arrays of middleware objects */

89

use: (middlewares: MiddlewareObj | MiddlewareObj[]) => MiddyfiedHandler<TEvent, TResult, TErr, TContext, TInternal>;

90

/** Attach before middleware function */

91

before: (middleware: MiddlewareFn<TEvent, TResult, TErr, TContext, TInternal>) => MiddyfiedHandler<TEvent, TResult, TErr, TContext, TInternal>;

92

/** Attach after middleware function */

93

after: (middleware: MiddlewareFn<TEvent, TResult, TErr, TContext, TInternal>) => MiddyfiedHandler<TEvent, TResult, TErr, TContext, TInternal>;

94

/** Attach error middleware function */

95

onError: (middleware: MiddlewareFn<TEvent, TResult, TErr, TContext, TInternal>) => MiddyfiedHandler<TEvent, TResult, TErr, TContext, TInternal>;

96

/** Replace the Lambda handler function */

97

handler: <TInputHandlerEventProps = TEvent, TInputHandlerResultProps = TResult>(

98

handler: MiddyInputHandler<TInputHandlerEventProps, TInputHandlerResultProps, TContext>

99

) => MiddyfiedHandler<TInputHandlerEventProps, TInputHandlerResultProps, TErr, TContext, TInternal>;

100

}

101

```

102

103

### Request Object

104

105

The request object passed to all middleware functions containing event, context, response, and internal state.

106

107

```typescript { .api }

108

interface Request<TEvent = any, TResult = any, TErr = Error, TContext extends LambdaContext = LambdaContext, TInternal extends Record<string, unknown> = {}> {

109

/** The Lambda event object */

110

event: TEvent;

111

/** The Lambda context object */

112

context: TContext;

113

/** Handler response (null initially, set by handler or middleware) */

114

response: TResult | null;

115

/** Optional early response value for short-circuiting */

116

earlyResponse?: TResult | null | undefined;

117

/** Error object (null initially, set if error occurs) */

118

error: TErr | null;

119

/** Internal state object for sharing data between middleware */

120

internal: TInternal;

121

}

122

```

123

124

### Middleware Function

125

126

Function signature for individual middleware functions.

127

128

```typescript { .api }

129

/**

130

* Middleware function signature

131

* @param request - The request object containing event, context, response, and internal state

132

* @returns Any value (can be Promise)

133

*/

134

type MiddlewareFn<TEvent = any, TResult = any, TErr = Error, TContext extends LambdaContext = LambdaContext, TInternal extends Record<string, unknown> = {}> = (

135

request: Request<TEvent, TResult, TErr, TContext, TInternal>

136

) => any;

137

```

138

139

### Middleware Object

140

141

Object structure for defining middleware with before, after, and error hooks.

142

143

```typescript { .api }

144

interface MiddlewareObj<TEvent = unknown, TResult = any, TErr = Error, TContext extends LambdaContext = LambdaContext, TInternal extends Record<string, unknown> = {}> {

145

/** Optional before middleware function */

146

before?: MiddlewareFn<TEvent, TResult, TErr, TContext, TInternal>;

147

/** Optional after middleware function */

148

after?: MiddlewareFn<TEvent, TResult, TErr, TContext, TInternal>;

149

/** Optional error middleware function */

150

onError?: MiddlewareFn<TEvent, TResult, TErr, TContext, TInternal>;

151

/** Optional middleware name for debugging */

152

name?: string;

153

}

154

```

155

156

### Plugin Configuration

157

158

Configuration object for lifecycle hooks and advanced functionality.

159

160

```typescript { .api }

161

interface PluginObject {

162

/** Internal state object shared across middleware */

163

internal?: any;

164

/** Hook called before prefetch operations */

165

beforePrefetch?: PluginHook;

166

/** Hook called at request start */

167

requestStart?: PluginHook;

168

/** Hook called before each middleware */

169

beforeMiddleware?: PluginHookWithMiddlewareName;

170

/** Hook called after each middleware */

171

afterMiddleware?: PluginHookWithMiddlewareName;

172

/** Hook called before handler execution */

173

beforeHandler?: PluginHook;

174

/** Timeout in milliseconds before Lambda timeout for early response */

175

timeoutEarlyInMillis?: number;

176

/** Function to call when timeout occurs */

177

timeoutEarlyResponse?: PluginHook;

178

/** Hook called after handler execution */

179

afterHandler?: PluginHook;

180

/** Hook called at request end */

181

requestEnd?: PluginHookPromise;

182

/** Enable AWS Lambda streaming response support */

183

streamifyResponse?: boolean;

184

}

185

```

186

187

### Handler Object

188

189

Object passed to Lambda handlers containing abort signal for timeout handling.

190

191

```typescript { .api }

192

interface MiddyHandlerObject {

193

/**

194

* An abort signal that will be canceled just before the lambda times out.

195

* Use this to cancel long-running operations gracefully.

196

*/

197

signal: AbortSignal;

198

}

199

```

200

201

## Usage Examples

202

203

### Multiple Middleware Objects

204

205

```javascript

206

import middy from "@middy/core";

207

208

const middleware1 = {

209

before: async (request) => {

210

console.log("Middleware 1 before");

211

},

212

after: async (request) => {

213

console.log("Middleware 1 after");

214

},

215

name: "middleware1"

216

};

217

218

const middleware2 = {

219

before: async (request) => {

220

console.log("Middleware 2 before");

221

},

222

onError: async (request) => {

223

console.log("Middleware 2 error handler");

224

},

225

name: "middleware2"

226

};

227

228

const handler = middy(lambdaHandler)

229

.use([middleware1, middleware2]);

230

```

231

232

### Plugin Configuration

233

234

```javascript

235

import middy from "@middy/core";

236

237

const pluginConfig = {

238

timeoutEarlyInMillis: 1000, // Timeout 1 second before Lambda timeout

239

timeoutEarlyResponse: () => {

240

throw new Error("Function timed out");

241

},

242

beforeMiddleware: (name) => console.log(`Starting ${name}`),

243

afterMiddleware: (name) => console.log(`Completed ${name}`),

244

internal: { startTime: Date.now() }

245

};

246

247

const handler = middy(lambdaHandler, pluginConfig);

248

```

249

250

### Handler Replacement

251

252

```javascript

253

import middy from "@middy/core";

254

255

// Create handler without initial function

256

const handler = middy()

257

.use(someMiddleware())

258

.handler(async (event, context, { signal }) => {

259

// Use abort signal for cancellation

260

const controller = new AbortController();

261

signal.addEventListener('abort', () => controller.abort());

262

263

return await fetch('https://api.example.com', {

264

signal: controller.signal

265

});

266

});

267

268

// Or replace an existing handler

269

const existingHandler = middy(lambdaHandler);

270

existingHandler.handler(async (event, context, { signal }) => {

271

// Completely replace the original handler logic

272

return { statusCode: 200, body: "New handler implementation" };

273

});

274

```

275

276

### Streaming Response

277

278

```javascript

279

import middy from "@middy/core";

280

281

const pluginConfig = {

282

streamifyResponse: true

283

};

284

285

const handler = middy(async (event, responseStream, context) => {

286

responseStream.write("Streaming data chunk 1\n");

287

responseStream.write("Streaming data chunk 2\n");

288

responseStream.end();

289

}, pluginConfig);

290

```

291

292

### Early Response

293

294

```javascript

295

import middy from "@middy/core";

296

297

const authMiddleware = {

298

before: async (request) => {

299

if (!request.event.headers.authorization) {

300

// Short-circuit the execution chain

301

request.earlyResponse = {

302

statusCode: 401,

303

body: JSON.stringify({ error: "Unauthorized" })

304

};

305

return;

306

}

307

}

308

};

309

310

const handler = middy(lambdaHandler)

311

.use(authMiddleware);

312

```

313

314

### Error Handling

315

316

```javascript

317

import middy from "@middy/core";

318

319

const errorHandlerMiddleware = {

320

onError: async (request) => {

321

console.error("Error occurred:", request.error);

322

323

// Modify response based on error

324

request.response = {

325

statusCode: 500,

326

body: JSON.stringify({

327

error: "Internal Server Error",

328

requestId: request.context.awsRequestId

329

})

330

};

331

}

332

};

333

334

const handler = middy(lambdaHandler)

335

.use(errorHandlerMiddleware);

336

```

337

338

## Constants

339

340

Package constants available for reference:

341

342

```typescript { .api }

343

/** Default no-op Lambda handler */

344

declare const defaultLambdaHandler: () => void;

345

346

/** Default plugin configuration object */

347

declare const defaultPluginConfig: PluginObject;

348

349

/** Chunk size for string iteration in streaming responses */

350

declare const stringIteratorSize: number; // 16384

351

```

352

353

The `defaultPluginConfig` object contains these default values:

354

355

```typescript { .api }

356

const defaultPluginConfig = {

357

timeoutEarlyInMillis: 5,

358

timeoutEarlyResponse: () => {

359

const err = new Error("[AbortError]: The operation was aborted.", {

360

cause: { package: "@middy/core" }

361

});

362

err.name = "TimeoutError";

363

throw err;

364

},

365

streamifyResponse: false

366

};

367

```

368

369

## Types

370

371

All TypeScript types and interfaces are exported in the `middy` namespace:

372

373

```typescript { .api }

374

declare namespace middy {

375

export type {

376

Request,

377

PluginHook,

378

PluginHookWithMiddlewareName,

379

PluginObject,

380

MiddlewareFn,

381

MiddlewareObj,

382

MiddyfiedHandler,

383

};

384

}

385

386

/** Plugin hook function signature */

387

type PluginHook = () => void;

388

389

/** Plugin hook function with middleware name parameter */

390

type PluginHookWithMiddlewareName = (middlewareName: string) => void;

391

392

/** Plugin hook function that can return a promise */

393

type PluginHookPromise = (request: Request) => Promise<unknown> | unknown;

394

395

/** Handler attachment function signature */

396

type AttachMiddlewareFn<TEvent = any, TResult = any, TErr = Error, TContext extends LambdaContext = LambdaContext, TInternal extends Record<string, unknown> = {}> = (

397

middleware: MiddlewareFn<TEvent, TResult, TErr, TContext, TInternal>

398

) => MiddyfiedHandler<TEvent, TResult, TErr, TContext, TInternal>;

399

400

/** Middleware use function signature */

401

type UseFn<TEvent = any, TResult = any, TErr = Error, TContext extends LambdaContext = LambdaContext, TInternal extends Record<string, unknown> = {}> = <TMiddleware extends MiddlewareObj<any, any, Error, any, any>>(

402

middlewares: TMiddleware | TMiddleware[]

403

) => MiddyfiedHandler<TEvent, TResult, TErr, TContext, TInternal>;

404

405

/** Handler function with optional MiddyHandlerObject parameter */

406

type MiddyInputHandler<TEvent, TResult, TContext extends LambdaContext = LambdaContext> = (

407

event: TEvent,

408

context: TContext,

409

opts: MiddyHandlerObject

410

) => undefined | Promise<TResult> | TResult;

411

412

/** Standard Promise-based handler function */

413

type MiddyInputPromiseHandler<TEvent, TResult, TContext extends LambdaContext = LambdaContext> = (

414

event: TEvent,

415

context: TContext

416

) => Promise<TResult>;

417

```

418

419

## Key Features

420

421

1. **Fluent API**: Chainable methods for attaching middleware

422

2. **Middleware Support**: Before, after, and error middleware execution

423

3. **Plugin System**: Lifecycle hooks for custom behaviors and monitoring

424

4. **Streaming Response**: Native AWS Lambda streaming response support

425

5. **Timeout Handling**: Early timeout detection with configurable responses

426

6. **Abort Signal**: Built-in AbortSignal support for graceful cancellation

427

7. **Early Response**: Middleware can short-circuit execution

428

8. **Type Safety**: Full TypeScript support with generic types

429

9. **ES Module**: Modern JavaScript module format with CommonJS compatibility

430

10. **Minimal Dependencies**: Lightweight core with no external dependencies