Skip to content
This repository was archived by the owner on Jan 28, 2025. It is now read-only.

Commit d9485f5

Browse files
next-aws-lambda can now be consumed using async signature (#131)
* feat: compat layer can now be consumed using async signature
1 parent 1d932a3 commit d9485f5

File tree

6 files changed

+253
-8
lines changed

6 files changed

+253
-8
lines changed

packages/next-aws-lambda/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,16 @@ Compat layer between next.js serverless page and AWS Lambda.
88
const compat = require("next-aws-lambda");
99
const page = require(".next/serverless/pages/somePage.js");
1010

11+
// using callback
12+
1113
module.exports.render = (event, context, callback) => {
1214
compat(page)(event, context, callback);
1315
};
16+
17+
// using async promise
18+
19+
module.exports.render = async (event, context, callback) => {
20+
const responsePromise = compat(page)(event, context); // don't pass the callback parameter
21+
return responsePromise;
22+
};
1423
```

packages/next-aws-lambda/__tests__/index.test.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@ describe("next-aws-lambda", () => {
3030
expect(mockRender).toBeCalledWith(req, res);
3131
expect(mockDefault).not.toBeCalled();
3232
});
33-
});
3433

35-
describe("next-aws-lambda", () => {
3634
it("passes request and response to next api", () => {
3735
const event = { foo: "bar" };
3836
const callback = () => {};
@@ -56,4 +54,26 @@ describe("next-aws-lambda", () => {
5654

5755
expect(mockDefault).toBeCalledWith(req, res);
5856
});
57+
58+
it("supports async signature", () => {
59+
expect.assertions(1);
60+
61+
const event = { foo: "bar" };
62+
const context = {};
63+
const page = {
64+
render: () => {}
65+
};
66+
const response = {
67+
statusCode: 200
68+
};
69+
compatLayer.mockReturnValue({
70+
responsePromise: Promise.resolve(response)
71+
});
72+
73+
const responsePromise = compat(page)(event, context);
74+
75+
return responsePromise.then(result => {
76+
expect(result).toEqual(response);
77+
});
78+
});
5979
});

packages/next-aws-lambda/index.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
const reqResMapper = require("./lib/compatLayer");
22

33
const handlerFactory = page => (event, _context, callback) => {
4-
const { req, res } = reqResMapper(event, callback);
4+
const { req, res, responsePromise } = reqResMapper(event, callback);
55
if (page.render instanceof Function) {
66
// Is a React component
77
page.render(req, res);
88
} else {
99
// Is an API
1010
page.default(req, res);
1111
}
12+
13+
if (responsePromise) {
14+
return responsePromise;
15+
}
1216
};
1317

1418
module.exports = handlerFactory;

packages/next-aws-lambda/lib/__tests__/compatLayer.response.test.js

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,24 @@ describe("compatLayer.response", () => {
2020
res.end();
2121
});
2222

23+
it("[Promise] statusCode writeHead 404", async () => {
24+
expect.assertions(1);
25+
26+
const { res, responsePromise } = create({
27+
requestContext: {
28+
path: "/"
29+
},
30+
headers: {}
31+
});
32+
33+
res.writeHead(404);
34+
res.end();
35+
36+
return responsePromise.then(response => {
37+
expect(response.statusCode).toEqual(404);
38+
});
39+
});
40+
2341
it("statusCode statusCode=200", done => {
2442
const { res } = create(
2543
{
@@ -38,6 +56,24 @@ describe("compatLayer.response", () => {
3856
res.end();
3957
});
4058

59+
it("[Promise] statusCode statusCode=200", () => {
60+
expect.assertions(1);
61+
62+
const { res, responsePromise } = create({
63+
requestContext: {
64+
path: "/"
65+
},
66+
headers: {}
67+
});
68+
69+
res.statusCode = 200;
70+
res.end();
71+
72+
return responsePromise.then(response => {
73+
expect(response.statusCode).toEqual(200);
74+
});
75+
});
76+
4177
it("writeHead headers", done => {
4278
const { res } = create(
4379
{
@@ -62,6 +98,30 @@ describe("compatLayer.response", () => {
6298
res.end();
6399
});
64100

101+
it("[Promise] writeHead headers", () => {
102+
expect.assertions(1);
103+
104+
const { res, responsePromise } = create({
105+
requestContext: {
106+
path: "/"
107+
},
108+
headers: {}
109+
});
110+
111+
res.writeHead(200, {
112+
"x-custom-1": "1",
113+
"x-custom-2": "2"
114+
});
115+
res.end();
116+
117+
return responsePromise.then(response => {
118+
expect(response.multiValueHeaders).toEqual({
119+
"x-custom-1": ["1"],
120+
"x-custom-2": ["2"]
121+
});
122+
});
123+
});
124+
65125
it("setHeader", done => {
66126
const { res } = create(
67127
{
@@ -84,6 +144,28 @@ describe("compatLayer.response", () => {
84144
res.end();
85145
});
86146

147+
it("[Promise] setHeader", () => {
148+
expect.assertions(1);
149+
150+
const { res, responsePromise } = create({
151+
requestContext: {
152+
path: "/"
153+
},
154+
headers: {}
155+
});
156+
157+
res.setHeader("x-custom-1", "1");
158+
res.setHeader("x-custom-2", "2");
159+
res.end();
160+
161+
return responsePromise.then(response => {
162+
expect(response.multiValueHeaders).toEqual({
163+
"x-custom-1": ["1"],
164+
"x-custom-2": ["2"]
165+
});
166+
});
167+
});
168+
87169
it("multi header support for api gateway", done => {
88170
const { res } = create(
89171
{
@@ -104,6 +186,25 @@ describe("compatLayer.response", () => {
104186
res.end();
105187
});
106188

189+
it("[Promise] multi header support for api gateway", () => {
190+
expect.assertions(1);
191+
192+
const { res, responsePromise } = create({
193+
requestContext: {
194+
path: "/"
195+
},
196+
headers: {}
197+
});
198+
res.setHeader("x-custom-1", ["1", "1"]);
199+
res.end();
200+
201+
return responsePromise.then(response => {
202+
expect(response.multiValueHeaders).toEqual({
203+
"x-custom-1": ["1", "1"]
204+
});
205+
});
206+
});
207+
107208
it("setHeader + removeHeader", done => {
108209
const { res } = create(
109210
{
@@ -126,6 +227,27 @@ describe("compatLayer.response", () => {
126227
res.end();
127228
});
128229

230+
it("[Promise] setHeader + removeHeader", () => {
231+
expect.assertions(1);
232+
233+
const { res, responsePromise } = create({
234+
requestContext: {
235+
path: "/"
236+
},
237+
headers: {}
238+
});
239+
res.setHeader("x-custom-1", "1");
240+
res.setHeader("x-custom-2", "2");
241+
res.removeHeader("x-custom-1");
242+
res.end();
243+
244+
return responsePromise.then(response => {
245+
expect(response.multiValueHeaders).toEqual({
246+
"x-custom-2": ["2"]
247+
});
248+
});
249+
});
250+
129251
it("getHeader/s", () => {
130252
const { res } = create({
131253
requestContext: {
@@ -162,6 +284,24 @@ describe("compatLayer.response", () => {
162284
res.end();
163285
});
164286

287+
it(`[Promise] res.write('ok')`, () => {
288+
expect.assertions(2);
289+
290+
const { res, responsePromise } = create({
291+
requestContext: {
292+
path: "/"
293+
},
294+
headers: {}
295+
});
296+
res.write("ok");
297+
res.end();
298+
299+
return responsePromise.then(response => {
300+
expect(response.isBase64Encoded).toEqual(false);
301+
expect(response.body).toEqual("ok");
302+
});
303+
});
304+
165305
it(`res.end('ok')`, done => {
166306
const { res } = create(
167307
{
@@ -180,6 +320,23 @@ describe("compatLayer.response", () => {
180320
res.end("ok");
181321
});
182322

323+
it(`[Promise] res.end('ok')`, () => {
324+
expect.assertions(2);
325+
326+
const { res, responsePromise } = create({
327+
requestContext: {
328+
path: "/"
329+
},
330+
headers: {}
331+
});
332+
res.end("ok");
333+
334+
return responsePromise.then(response => {
335+
expect(response.isBase64Encoded).toEqual(false);
336+
expect(response.body).toEqual("ok");
337+
});
338+
});
339+
183340
it("req.pipe(res)", done => {
184341
const { req, res } = create(
185342
{
@@ -199,6 +356,24 @@ describe("compatLayer.response", () => {
199356
res.end("ok");
200357
});
201358

359+
it("[Promise] req.pipe(res)", () => {
360+
expect.assertions(2);
361+
362+
const { res, responsePromise } = create({
363+
requestContext: {
364+
path: "/"
365+
},
366+
headers: {}
367+
});
368+
369+
res.end("ok");
370+
371+
return responsePromise.then(response => {
372+
expect(response.isBase64Encoded).toEqual(false);
373+
expect(response.body).toEqual("ok");
374+
});
375+
});
376+
202377
it("base64 support", done => {
203378
process.env.BINARY_SUPPORT = "yes";
204379
const { res } = create(
@@ -217,4 +392,23 @@ describe("compatLayer.response", () => {
217392
);
218393
res.end("ok");
219394
});
395+
396+
it("[Promise] base64 support", () => {
397+
expect.assertions(2);
398+
399+
process.env.BINARY_SUPPORT = "yes";
400+
const { res, responsePromise } = create({
401+
requestContext: {
402+
path: "/"
403+
},
404+
headers: {}
405+
});
406+
407+
res.end("ok");
408+
409+
return responsePromise.then(response => {
410+
expect(response.body).toEqual(Buffer.from("ok").toString("base64"));
411+
expect(response.isBase64Encoded).toEqual(true);
412+
});
413+
});
220414
});

packages/next-aws-lambda/lib/compatLayer.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const reqResMapper = (event, callback) => {
99
statusCode: 200,
1010
multiValueHeaders: {}
1111
};
12+
let responsePromise;
1213

1314
const req = new Stream.Readable();
1415
req.url = (event.requestContext.path || event.path || "").replace(
@@ -93,19 +94,35 @@ const reqResMapper = (event, callback) => {
9394
res.getHeaders = () => {
9495
return res.headers;
9596
};
96-
res.end = text => {
97+
98+
const onResEnd = (callback, resolve) => text => {
9799
if (text) res.write(text);
98100
response.body = Buffer.from(response.body).toString(
99101
base64Support ? "base64" : undefined
100102
);
101103
response.multiValueHeaders = res.headers;
102104
res.writeHead(response.statusCode);
103105
fixApiGatewayMultipleHeaders();
104-
callback(null, response);
106+
107+
if (callback) {
108+
callback(null, response);
109+
} else {
110+
resolve(response);
111+
}
105112
};
113+
114+
if (typeof callback === "function") {
115+
res.end = onResEnd(callback);
116+
} else {
117+
responsePromise = new Promise(resolve => {
118+
res.end = onResEnd(null, resolve);
119+
});
120+
}
121+
106122
if (event.body) {
107123
req.push(event.body, event.isBase64Encoded ? "base64" : undefined);
108124
}
125+
109126
req.push(null);
110127

111128
function fixApiGatewayMultipleHeaders() {
@@ -116,7 +133,7 @@ const reqResMapper = (event, callback) => {
116133
}
117134
}
118135

119-
return { req, res };
136+
return { req, res, responsePromise };
120137
};
121138

122139
module.exports = reqResMapper;

0 commit comments

Comments
 (0)