Skip to content

Commit 27566f5

Browse files
committed
Remove dependency on in-request-handler, added hooks
1 parent 8fd306e commit 27566f5

8 files changed

+688
-585
lines changed

package-lock.json

Lines changed: 567 additions & 564 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,21 +40,20 @@
4040
"main": "./dist/compile/lambda",
4141
"types": "./dist/compile/lambda.d.ts",
4242
"dependencies": {
43-
"in-process-request": "^0.3.1",
4443
"isutf8": "^4.0.0",
4544
"light-my-request": "^5.6.1"
4645
},
4746
"devDependencies": {
4847
"@types/compression": "^1.7.2",
4948
"@types/cookie-parser": "^1.4.3",
5049
"@types/express": "^4.17.14",
51-
"@types/jest": "^29.2.1",
52-
"@types/node": "^18.11.8",
50+
"@types/jest": "^29.2.2",
51+
"@types/node": "^18.11.9",
5352
"compression": "^1.7.4",
5453
"cookie-parser": "^1.4.6",
5554
"ejs": "^3.1.8",
5655
"express": "^4.18.2",
57-
"jest": "^29.2.2",
56+
"jest": "^29.3.1",
5857
"prettier": "^2.7.1",
5958
"ts-jest": "^29.0.3",
6059
"ts-node": "^10.9.1",

src/handlers/fastifyHandler.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Server, RequestListener } from "http"
2+
3+
interface MockServer extends Server {
4+
__handler: RequestListener
5+
}
6+
7+
const serverFactory = (handler: RequestListener): MockServer => {
8+
return {
9+
__handler: handler,
10+
on: () => {},
11+
once: () => {},
12+
removeListener: () => {},
13+
address: () => "0.0.0.0",
14+
listen: (_: unknown, cb: () => void) => {
15+
cb()
16+
},
17+
} as any
18+
}
19+
20+
type Output = (options: object) => Promise<RequestListener>
21+
type FastifyBuilder = (options: object) => any
22+
23+
const fastifyHandler =
24+
(fastifyBuilder: FastifyBuilder): Output =>
25+
(options = {}) => {
26+
const app = fastifyBuilder({ ...options, serverFactory })
27+
return app.listen(0).then(() => app.server.__handler)
28+
}
29+
30+
export default fastifyHandler

src/handlers/fastifyV4Handler.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const fastifyV4Handler = (app: any) =>
2+
new Promise((resolve, reject) => {
3+
app.ready((err: Error) => {
4+
if (err) {
5+
reject(err)
6+
} else {
7+
resolve(app.routing)
8+
}
9+
})
10+
})
11+
12+
export default fastifyV4Handler

src/handlers/hapiListener.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { EventEmitter } from "events"
2+
import { IncomingMessage, ServerResponse } from "http"
3+
4+
type Callback = () => void
5+
6+
export class HapiListener extends EventEmitter {
7+
listen(_port: any, maybeCallback?: any, maybeCallback2?: any) {
8+
let callback: Callback | undefined =
9+
typeof maybeCallback === "function" ? maybeCallback : undefined
10+
if (!callback) {
11+
callback =
12+
typeof maybeCallback2 === "function" ? maybeCallback2 : undefined
13+
}
14+
if (callback) {
15+
callback()
16+
}
17+
}
18+
19+
get handler() {
20+
return (req: IncomingMessage, res: ServerResponse) =>
21+
this.emit("request", req, res)
22+
}
23+
}

src/handlers/nestHandler.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const getNestHandler = async (nestApp: any) => {
2+
!nestApp.isInitialized && (await nestApp.init())
3+
// nestApp.isListening = true;
4+
return nestApp.httpAdapter.getInstance()
5+
}
6+
7+
export default getNestHandler

src/lambda.ts

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import { RequestListener } from "http"
2-
import inProcessRequestHandler from "in-process-request"
2+
import { HapiListener } from "./handlers/hapiListener"
33
import * as apigw from "./types"
44
import eventToRequestOptions from "./eventToRequestOptions"
55
import { inProcessResponseToLambdaResponse, errorResponse } from "./response"
66
import { inject } from "light-my-request"
7+
import getNestHandler from "./handlers/nestHandler"
8+
import fastifyHandler from "./handlers/fastifyHandler"
9+
import fastifyV4Handler from "./handlers/fastifyV4Handler"
710

811
declare namespace handler {
912
type APIGatewayEvent = apigw.APIGatewayEvent
@@ -16,7 +19,6 @@ declare namespace handler {
1619
) => Promise<handler.LambdaResponse>
1720
}
1821

19-
type F<A, B> = (a: A) => B
2022
type Nullable<T> = T | null
2123
type PromiseFactory<A> = () => Promise<A>
2224

@@ -31,34 +33,58 @@ const eventSupportsCookies = (event: handler.APIGatewayEvent): boolean => {
3133
return event.version === "2.0" && !eventHasMultiValueHeaders(event)
3234
}
3335

36+
interface Options {
37+
beforeDispatch?: (r: apigw.APIGatewayEvent) => Promise<apigw.APIGatewayEvent>
38+
beforeReturn?: (r: apigw.LambdaResponse) => Promise<apigw.LambdaResponse>
39+
onError?: (e: Error) => Promise<void>
40+
}
41+
3442
const handlerBuilder = (
35-
appFn: PromiseFactory<RequestListener>
43+
appFn: PromiseFactory<RequestListener>,
44+
options?: Options
3645
): handler.APIGatewayEventHandler => {
3746
let dispatch: Nullable<RequestListener>
3847
return async (event, ctx) => {
3948
if (!dispatch) {
4049
dispatch = await appFn()
4150
}
4251
try {
43-
const reqOptions = eventToRequestOptions(event, ctx)
52+
let theEvent = event
53+
if (options?.beforeDispatch) {
54+
theEvent = await options.beforeDispatch(theEvent)
55+
}
56+
const reqOptions = eventToRequestOptions(theEvent, ctx)
4457
const mockResponse = await inject(dispatch, reqOptions)
45-
return inProcessResponseToLambdaResponse(
58+
let response = inProcessResponseToLambdaResponse(
4659
mockResponse,
4760
eventHasMultiValueHeaders(event),
4861
eventSupportsCookies(event)
4962
)
63+
if (options?.beforeReturn) {
64+
response = await options.beforeReturn(response)
65+
}
66+
return response
5067
} catch (e) {
51-
console.error(e)
68+
if (options?.onError) {
69+
try {
70+
await options.onError(e as Error)
71+
} catch (e2) {
72+
console.error(e)
73+
}
74+
} else {
75+
console.error(e)
76+
}
5277
return errorResponse()
5378
}
5479
}
5580
}
5681

57-
const handler = (app: RequestListener) =>
58-
handlerBuilder(() => Promise.resolve(app))
82+
const handler = (app: RequestListener, options?: Options) =>
83+
handlerBuilder(() => Promise.resolve(app), options)
5984
handler.deferred = handlerBuilder
60-
handler.HapiListener = inProcessRequestHandler.HapiListener
61-
handler.nestHandler = inProcessRequestHandler.nestHandler
62-
handler.fastifyHandler = inProcessRequestHandler.fastifyHandler
85+
handler.HapiListener = HapiListener
86+
handler.nestHandler = getNestHandler
87+
handler.fastifyHandler = fastifyHandler
88+
handler.fastifyV4Handler = fastifyV4Handler
6389

6490
export = handler

test/integration.deferred.test.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ describe("integration for deferred app", () => {
5454
})
5555

5656
it("handler returns rejected promise if app cannot be initialized", async () => {
57-
const failingHandler = lambda.deferred(() =>
58-
Promise.reject(new Error("failed to initialize app"))
57+
const failingHandler = lambda.deferred(
58+
() => Promise.reject(new Error("failed to initialize app")),
59+
{ onError: async () => undefined }
5960
)
6061
const myEvent = {
6162
path: "/static/file.png",
@@ -75,10 +76,12 @@ describe("integration for deferred app", () => {
7576
})
7677

7778
it("returns 500 if there is a problem with the request", async () => {
78-
const failingApp = lambda.deferred(() =>
79-
Promise.resolve(() => {
80-
throw new Error("failed")
81-
})
79+
const failingApp = lambda.deferred(
80+
() =>
81+
Promise.resolve(() => {
82+
throw new Error("failed")
83+
}),
84+
{ onError: async () => undefined }
8285
)
8386
const myEvent = {
8487
path: "/static/file.png",

0 commit comments

Comments
 (0)