Skip to content

Commit 45edbac

Browse files
authored
create ASync and Sync Handlers (#394)
1 parent 77094a2 commit 45edbac

File tree

2 files changed

+128
-12
lines changed

2 files changed

+128
-12
lines changed
Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
11
import { Handler } from 'aws-lambda';
22

3+
export type SyncHandler<T extends Handler> = (
4+
event: Parameters<T>[0],
5+
context: Parameters<T>[1],
6+
callback: Parameters<T>[2],
7+
) => void;
8+
9+
export type AsyncHandler<T extends Handler> = (
10+
event: Parameters<T>[0],
11+
context: Parameters<T>[1],
12+
) => Promise<NonNullable<Parameters<Parameters<T>[2]>[1]>>;
13+
314
interface LambdaInterface {
4-
handler: Handler
15+
handler: SyncHandler<Handler> | AsyncHandler<Handler>
516
}
617

718
export {
8-
LambdaInterface,
19+
LambdaInterface
920
};
Lines changed: 115 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,128 @@
1+
import { Handler } from 'aws-lambda';
12
import { Callback, Context } from 'aws-lambda';
2-
import { ContextExamples, LambdaInterface } from '../../src';
3+
import { ContextExamples, SyncHandler, AsyncHandler, LambdaInterface } from '../../src';
34

4-
describe('LambdaInterface', () => {
5-
test('it compiles', async () => {
5+
describe('LambdaInterface with arrow function', () => {
6+
test('it compiles when given a callback', async () => {
67
class LambdaFunction implements LambdaInterface {
7-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
8-
// @ts-ignore
9-
public handler<TEvent, TResult>(
10-
_event: TEvent,
11-
context: Context,
12-
_callback: Callback<TResult>,
13-
): void | Promise<TResult> {
8+
9+
public handler: SyncHandler<Handler> = async (_event: unknown, context: Context, _callback: Callback) => {
1410
context.done();
1511
context.fail(new Error('test Error'));
1612
context.succeed('test succeed');
1713
context.getRemainingTimeInMillis();
14+
_callback(null, 'Hello World');
15+
};
16+
}
17+
18+
await new LambdaFunction().handler({}, ContextExamples.helloworldContext, () => console.log('Lambda invoked!'));
19+
});
20+
21+
test('it compiles when not given a callback', async () => {
22+
class LambdaFunction implements LambdaInterface {
23+
24+
public handler: AsyncHandler<Handler> = async (_event: unknown, context: Context) => {
25+
context.getRemainingTimeInMillis();
26+
};
27+
}
28+
29+
await new LambdaFunction().handler({}, ContextExamples.helloworldContext);
30+
});
31+
});
32+
33+
describe('LambdaInterface with standard function', () => {
34+
test('it compiles when given a callback', async () => {
35+
class LambdaFunction implements LambdaInterface {
36+
37+
public handler(_event: unknown, context: Context, _callback: Callback): void {
38+
context.getRemainingTimeInMillis();
39+
_callback(null, 'Hello World');
1840
}
1941
}
2042

2143
await new LambdaFunction().handler({}, ContextExamples.helloworldContext, () => console.log('Lambda invoked!'));
2244
});
45+
46+
test('it compiles when not given a callback', async () => {
47+
class LambdaFunction implements LambdaInterface {
48+
49+
public async handler (_event: unknown, context: Context): Promise<string> {
50+
context.getRemainingTimeInMillis();
51+
52+
return new Promise((resolve) => {
53+
resolve('test promise');
54+
});
55+
}
56+
}
57+
58+
await new LambdaFunction().handler({}, ContextExamples.helloworldContext);
59+
});
60+
61+
});
62+
63+
describe('LambdaInterface with decorator', () => {
64+
type HandlerMethodDecorator = (
65+
target: LambdaInterface,
66+
propertyKey: string | symbol,
67+
descriptor: TypedPropertyDescriptor<SyncHandler<Handler>> | TypedPropertyDescriptor<AsyncHandler<Handler>>
68+
) => void;
69+
70+
class DummyModule {
71+
72+
public dummyDecorator(): HandlerMethodDecorator {
73+
return (target, _propertyKey, descriptor) => {
74+
const originalMethod = descriptor.value;
75+
76+
descriptor.value = ( async (event, context, callback) => {
77+
78+
let result: unknown;
79+
try {
80+
console.log(`Invoking ${String(_propertyKey)}`);
81+
result = await originalMethod?.apply(this, [ event, context, callback ]);
82+
console.log(`Invoked ${String(_propertyKey)}`);
83+
} catch (error) {
84+
throw error;
85+
} finally {
86+
console.log(`Finally from decorator`);
87+
}
88+
89+
return result;
90+
});
91+
92+
return descriptor;
93+
};
94+
}
95+
}
96+
97+
const dummyModule = new DummyModule();
98+
99+
test('decorator without callback compile', async () => {
100+
101+
// WHEN
102+
class LambdaFunction implements LambdaInterface {
103+
104+
@dummyModule.dummyDecorator()
105+
public async handler(_event: unknown, context: Context): Promise<unknown> {
106+
context.getRemainingTimeInMillis();
107+
108+
return 'test';
109+
}
110+
}
111+
112+
await new LambdaFunction().handler({}, ContextExamples.helloworldContext);
113+
});
114+
115+
test('decorator with callback compile', async () => {
116+
117+
// WHEN
118+
class LambdaFunction implements LambdaInterface {
119+
120+
@dummyModule.dummyDecorator()
121+
public handler(_event: unknown, context: Context, _callback: Callback): void {
122+
context.getRemainingTimeInMillis();
123+
}
124+
}
125+
126+
await new LambdaFunction().handler({}, ContextExamples.helloworldContext, () => console.log('Lambda invoked!'));
127+
});
23128
});

0 commit comments

Comments
 (0)