Skip to content

Commit b327588

Browse files
committed
feat(event-handler): add middleare registration and composition to rest handler
1 parent f85dfbf commit b327588

File tree

4 files changed

+405
-3
lines changed

4 files changed

+405
-3
lines changed

packages/event-handler/src/rest/BaseRouter.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type {
1010
ErrorHandler,
1111
ErrorResolveOptions,
1212
HttpMethod,
13+
Middleware,
1314
Path,
1415
RouteHandler,
1516
RouteOptions,
@@ -30,13 +31,18 @@ import {
3031
} from './errors.js';
3132
import { Route } from './Route.js';
3233
import { RouteHandlerRegistry } from './RouteHandlerRegistry.js';
33-
import { isAPIGatewayProxyEvent, isHttpMethod } from './utils.js';
34+
import {
35+
composeMiddleware,
36+
isAPIGatewayProxyEvent,
37+
isHttpMethod,
38+
} from './utils.js';
3439

3540
abstract class BaseRouter {
3641
protected context: Record<string, unknown>;
3742

3843
protected readonly routeRegistry: RouteHandlerRegistry;
3944
protected readonly errorHandlerRegistry: ErrorHandlerRegistry;
45+
protected readonly middlwares: Middleware[] = [];
4046

4147
/**
4248
* A logger instance to be used for logging debug, warning, and error messages.
@@ -140,6 +146,10 @@ abstract class BaseRouter {
140146
};
141147
}
142148

149+
public use(middleware: Middleware): void {
150+
this.middlwares.push(middleware);
151+
}
152+
143153
/**
144154
* Resolves an API Gateway event by routing it to the appropriate handler
145155
* and converting the result to an API Gateway proxy result. Handles errors
@@ -185,14 +195,24 @@ abstract class BaseRouter {
185195
throw new NotFoundError(`Route ${path} for method ${method} not found`);
186196
}
187197

188-
const result = await route.handler.apply(options?.scope ?? this, [
198+
const handler =
199+
options?.scope != null
200+
? route.handler.bind(options.scope)
201+
: route.handler;
202+
203+
const middleware = composeMiddleware([...this.middlwares]);
204+
205+
const result = await middleware(
189206
route.params,
190207
{
191208
event,
192209
context,
193210
request,
194211
},
195-
]);
212+
() => handler(route.params, { event, context, request })
213+
);
214+
215+
if (result === undefined) throw new InternalServerError();
196216

197217
return await handlerResultToProxyResult(result);
198218
} catch (error) {

packages/event-handler/src/rest/utils.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ import { isRecord, isString } from '@aws-lambda-powertools/commons/typeutils';
22
import type { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
33
import type {
44
CompiledRoute,
5+
HandlerResponse,
56
HttpMethod,
7+
Middleware,
68
Path,
9+
RequestOptions,
710
ValidationResult,
811
} from '../types/rest.js';
912
import {
@@ -105,3 +108,39 @@ export const isAPIGatewayProxyResult = (
105108
typeof result.isBase64Encoded === 'boolean')
106109
);
107110
};
111+
112+
export const composeMiddleware = (middlewares: Middleware[]): Middleware => {
113+
return async (
114+
params: Record<string, string>,
115+
options: RequestOptions,
116+
next: () => Promise<HandlerResponse | void>
117+
): Promise<HandlerResponse | void> => {
118+
let index = -1;
119+
let result: HandlerResponse | undefined;
120+
121+
const dispatch = async (i: number): Promise<void> => {
122+
if (i <= index) throw new Error('next() called multiple times');
123+
index = i;
124+
125+
if (i === middlewares.length) {
126+
const nextResult = await next();
127+
if (nextResult !== undefined) {
128+
result = nextResult;
129+
}
130+
return;
131+
}
132+
133+
const middleware = middlewares[i];
134+
const middlewareResult = await middleware(params, options, () =>
135+
dispatch(i + 1)
136+
);
137+
138+
if (middlewareResult !== undefined) {
139+
result = middlewareResult;
140+
}
141+
};
142+
143+
await dispatch(0);
144+
return result;
145+
};
146+
};

packages/event-handler/src/types/rest.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ type RouteOptions = {
7777
path: Path;
7878
};
7979

80+
type NextFunction = () => Promise<HandlerResponse | void>;
81+
82+
type Middleware = (
83+
params: Record<string, string>,
84+
options: RequestOptions,
85+
next: NextFunction
86+
) => Promise<void | HandlerResponse>;
87+
8088
type RouteRegistryOptions = {
8189
/**
8290
* A logger instance to be used for logging debug, warning, and error messages.
@@ -111,6 +119,7 @@ export type {
111119
HandlerResponse,
112120
HttpStatusCode,
113121
HttpMethod,
122+
Middleware,
114123
Path,
115124
RequestOptions,
116125
RouterOptions,

0 commit comments

Comments
 (0)