Skip to content

Commit a1a6d56

Browse files
Merge pull request #225 from sliit-foss/feature/async-handler-generics
Feat(functions): added generic support to async handlers
2 parents cc12979 + 81c227f commit a1a6d56

File tree

4 files changed

+17
-23
lines changed

4 files changed

+17
-23
lines changed

packages/functions/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"express": "*"
2121
},
2222
"devDependencies": {
23-
"@types/express": "*"
23+
"express": "*"
2424
},
2525
"repository": {
2626
"type": "git",

packages/functions/src/async.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { _traced } from "./traced";
66
const logger = moduleLogger("tracer");
77

88
const _asyncHandler =
9-
(fn: RequestHandler, trace = false) =>
9+
(fn, trace = false) =>
1010
async (req: Request, res: Response & Record<string, any>, next: NextFunction) => {
1111
let fnName: string;
1212
try {
@@ -34,44 +34,42 @@ const _asyncHandler =
3434
* @description Creates a function which invokes the given function asynchronously and calls the `next` function in case of an error thereby preventing the application from crashing.
3535
* @param fn The function to be invoked asynchronously
3636
*/
37-
export const asyncHandler = (fn: RequestHandler): RequestHandler => _asyncHandler(fn);
37+
export const asyncHandler = <P = RequestHandler>(fn: P) => _asyncHandler(fn) as P;
3838

3939
/**
4040
* @description Creates a function which invokes the given function asynchronously with tracing and calls the `next` function in case of an error thereby preventing the application from crashing.
4141
* @param fn The function to be invoked asynchronously
4242
*/
43-
export const tracedAsyncHandler = (fn: RequestHandler): RequestHandler => _asyncHandler(fn, true);
43+
export const tracedAsyncHandler = <P = RequestHandler>(fn: P) => _asyncHandler(fn, true) as P;
4444

4545
/**
4646
* @description Same as the `tracedAsyncHandler` but the log upon failure is a warning log
4747
* @param fn The function to be invoked asynchronously
4848
*/
49-
export const fallibleAsyncHandler =
50-
(fn: RequestHandler): RequestHandler =>
51-
async (req, res: Response & Record<string, any>, next) => {
49+
export const fallibleAsyncHandler = <P extends RequestHandler>(fn: P) =>
50+
(async (req, res: Response & Record<string, any>, next) => {
5251
try {
5352
await _traced(fn.bind(this, req, res, next), {}, _fnName(fn), null, true);
5453
if (!res.headersSent) next();
5554
} catch (err) {
5655
res.errorLogged = true;
5756
if (!res.headersSent) next(err);
5857
}
59-
};
58+
}) as P;
6059

6160
/**
6261
* @description A more stripped down version of asyncHandler without any logs
6362
* @param fn The function to be invoked asynchronously
6463
*/
65-
export const plainAsyncHandler =
66-
(fn: RequestHandler): RequestHandler =>
67-
async (req, res, next) => {
64+
export const plainAsyncHandler = <P extends RequestHandler>(fn: P) =>
65+
(async (req, res, next) => {
6866
try {
6967
const result = fn(req, res, next) as any;
7068
if (result instanceof Promise) await result;
7169
} catch (e) {
7270
next(e);
7371
}
74-
};
72+
}) as P;
7573

7674
export default {
7775
asyncHandler,

packages/functions/test/async.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const { mockLogger } = require("./__mocks__");
22

3-
import { Request, Response } from "express";
3+
import { Request, Response, NextFunction } from "express";
44
import { asyncHandler, tracedAsyncHandler, fallibleAsyncHandler, plainAsyncHandler } from "../src";
55
import { coloredFnName } from "../src/utils";
66

@@ -14,43 +14,43 @@ describe("asyncHandler", () => {
1414
const mockNext = jest.fn();
1515

1616
test("test async handler", async () => {
17-
function testFunction() {
17+
function testFunction(_: Request, __: Response, ___: NextFunction) {
1818
return "test";
1919
}
2020
await asyncHandler(testFunction)(mockReq, mockRes, mockNext);
2121
expect(mockLogger.info).not.toHaveBeenCalled();
2222
expect(mockNext).toHaveBeenCalled();
2323
});
2424
test("test async handler with error", async () => {
25-
function testFunction() {
25+
function testFunction(_: Request, __: Response, ___: NextFunction) {
2626
throw new Error("test error");
2727
}
2828
await asyncHandler(testFunction)(mockReq, mockRes, mockNext);
2929
expect(mockLogger.error).toHaveBeenCalled();
3030
expect(mockNext).toHaveBeenCalled();
3131
});
3232
test("test traced async handler", async () => {
33-
await tracedAsyncHandler(function testTracedFunction() {
33+
await tracedAsyncHandler(function testTracedFunction(_: Request, __: Response, ___: NextFunction) {
3434
return "test";
3535
})(mockReq, mockRes, mockNext);
3636
expect(mockLogger.info).toHaveBeenCalledWith(`${coloredFnName("testTracedFunction")} execution initiated`, {});
3737
expect(mockNext).toHaveBeenCalled();
3838
});
3939
test("test fallible async handler", async () => {
40-
await fallibleAsyncHandler(function testTracedFunction() {
40+
await fallibleAsyncHandler(function testTracedFunction(_: Request, __: Response, ___: NextFunction) {
4141
throw new Error("test error");
4242
})(mockReq, mockRes, mockNext);
4343
expect(mockLogger.warn).toHaveBeenCalled();
4444
expect(mockNext).toHaveBeenCalled();
4545
});
4646
test("test plain async handler with async function", async () => {
47-
await plainAsyncHandler(async () => {
47+
await plainAsyncHandler(async (_: Request, __: Response, ___: NextFunction) => {
4848
throw new Error("test");
4949
})(mockReq, mockRes, mockNext);
5050
expect(mockNext).toHaveBeenCalled();
5151
});
5252
test("test plain async handler with normal function", async () => {
53-
await plainAsyncHandler(() => {
53+
await plainAsyncHandler((_: Request, __: Response, ___: NextFunction) => {
5454
throw new Error("test");
5555
})(mockReq, mockRes, mockNext);
5656
expect(mockNext).toHaveBeenCalled();

pnpm-lock.yaml

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

0 commit comments

Comments
 (0)