Skip to content

Commit 9eebbe8

Browse files
committed
use light-my-request
1 parent 1bd2be8 commit 9eebbe8

File tree

9 files changed

+163
-76
lines changed

9 files changed

+163
-76
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
runs-on: ubuntu-latest
1010
strategy:
1111
matrix:
12-
node: [ '12', '14', '16' ]
12+
node: [ '14', '16', '18' ]
1313
name: Node ${{ matrix.node }}
1414

1515
steps:

package-lock.json

Lines changed: 57 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
"types": "./dist/compile/lambda.d.ts",
4040
"dependencies": {
4141
"in-process-request": "^0.3.1",
42-
"isutf8": "^4.0.0"
42+
"isutf8": "^4.0.0",
43+
"light-my-request": "^5.6.1"
4344
},
4445
"devDependencies": {
4546
"@types/compression": "^1.7.2",

src/eventToRequestOptions.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import * as url from 'url';
1+
import {type InjectOptions} from "light-my-request"
22

3-
import { InProcessRequestOptions } from 'in-process-request';
43
import { APIGatewayEvent, StringMap, LambdaContext } from './types';
54

65
const getValuesFromStringAndMultiString = (stringMap: StringMap<string> | null | undefined, multiStringMap: StringMap<string[]> | null | undefined, lcKeys = true): StringMap<string> => {
@@ -17,7 +16,7 @@ const getValuesFromStringAndMultiString = (stringMap: StringMap<string> | null |
1716
return retVal;
1817
}
1918

20-
const eventToRequestOptions = (event: APIGatewayEvent, ctx?: LambdaContext): InProcessRequestOptions => {
19+
const eventToRequestOptions = (event: APIGatewayEvent, ctx?: LambdaContext): InjectOptions => {
2120
let remoteAddress:string | undefined = undefined;
2221
let ssl = false;
2322
const queryStringParams = getValuesFromStringAndMultiString(event.queryStringParameters, event.multiValueQueryStringParameters, false);
@@ -64,11 +63,14 @@ const eventToRequestOptions = (event: APIGatewayEvent, ctx?: LambdaContext): InP
6463
path = event.requestContext.http.path
6564
}
6665
return {
67-
method,
68-
path: url.format({ pathname: path, query: queryStringParams }),
66+
method: (method || 'get') as any,
67+
path: {
68+
pathname: path!!,
69+
query: queryStringParams,
70+
protocol: ssl ? 'https' : 'http',
71+
},
6972
headers: headers,
70-
body: Buffer.from(event.body || '', event.isBase64Encoded ? 'base64' : 'utf8'),
71-
ssl,
73+
payload: Buffer.from(event.body || '', event.isBase64Encoded ? 'base64' : 'utf8'),
7274
remoteAddress
7375
};
7476
}

src/lambda.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import inProcessRequestHandler from 'in-process-request';
33
import * as apigw from './types';
44
import eventToRequestOptions from './eventToRequestOptions'
55
import { inProcessResponseToLambdaResponse, errorResponse } from './response';
6-
import { MockRequestOptions, MockResponse } from 'in-process-request/dist/compile/httpMock';
6+
import { inject } from 'light-my-request';
77

88
declare namespace handler {
99
type APIGatewayEvent = apigw.APIGatewayEvent;
@@ -26,15 +26,14 @@ const eventSupportsCookies = (event: handler.APIGatewayEvent): boolean => {
2626
}
2727

2828
const handlerBuilder = (appFn: PromiseFactory<RequestListener>): handler.APIGatewayEventHandler => {
29-
let appHandler: Nullable<F<MockRequestOptions, Promise<MockResponse>>>;
29+
let dispatch: Nullable<RequestListener>;
3030
return async (event, ctx) => {
31-
if (!appHandler) {
32-
const resolvedApp = await appFn();
33-
appHandler = inProcessRequestHandler(resolvedApp);
31+
if (!dispatch) {
32+
dispatch = await appFn();
3433
}
3534
try {
3635
const reqOptions = eventToRequestOptions(event, ctx);
37-
const mockResponse = await appHandler(reqOptions);
36+
const mockResponse = await inject(dispatch, reqOptions);
3837
return inProcessResponseToLambdaResponse(mockResponse, eventHasMultiValueHeaders(event), eventSupportsCookies(event));
3938
} catch (e) {
4039
console.error(e);

src/response.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,37 @@
1-
import { InProcessResponse } from 'in-process-request';
21
import { LambdaResponse } from './types';
32
import fixResponseHeaders from './fixResponseHeaders'
43
import isUtf8 from 'isutf8'
4+
import { Response } from 'light-my-request';
5+
import { OutgoingHttpHeaders } from 'http';
56

67
type Encoding = 'base64' | 'utf8'
7-
export const inProcessResponseToLambdaResponse = (response: InProcessResponse, supportMultiHeaders: boolean, supportCookies: boolean): LambdaResponse => {
8+
export const inProcessResponseToLambdaResponse = (response: Response, supportMultiHeaders: boolean, supportCookies: boolean): LambdaResponse => {
89
const encoding = getEncoding(response);
910
return {
1011
statusCode: response.statusCode,
11-
body: response.body.toString(encoding),
12+
body: response.rawPayload.toString(encoding),
1213
isBase64Encoded: encoding === 'base64',
1314
...fixResponseHeaders(response.headers, supportMultiHeaders, supportCookies),
1415
};
1516
};
1617

17-
const getEncoding = (response: InProcessResponse): Encoding => {
18+
const isUTF8 = (headers: OutgoingHttpHeaders): boolean => {
19+
if (headers["content-encoding"]) {
20+
return false
21+
}
22+
const contentType = (headers["content-type"] as string) || ""
23+
return contentType.match(/charset=(utf-8|"utf-8")$/i) ? true : false
24+
}
25+
const getEncoding = (response: Response): Encoding => {
1826
// APi Gateway REST API cannot handle html responses encoded as base64
19-
if (response.isUTF8) {
27+
if (isUTF8(response.headers)) {
2028
return 'utf8';
2129
}
2230
const contentType = (response.headers['content-type'] as string || '').toLowerCase();
2331
const isJson = (): boolean => contentType.startsWith('application/json')
2432
const isText = (): boolean => contentType.startsWith('text/')
2533
const maybeUtf8 = isJson() || isText()
26-
if (maybeUtf8 && isUtf8(response.body)) {
34+
if (maybeUtf8 && isUtf8(response.rawPayload)) {
2735
return 'utf8'
2836
}
2937
return 'base64'

test/eventToRequestOptions.test.ts

Lines changed: 56 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,13 @@ describe('eventToRequestOptions', () => {
1313
const reqOpts = eventToRequestOptions(eventRestApi);
1414
expect(reqOpts).toEqual({
1515
"method": "GET",
16-
"path": "/inspect?param=ab%20cd",
16+
"path": {
17+
pathname: "/inspect",
18+
protocol: 'https',
19+
query: {"param": "ab cd"},
20+
},
1721
"remoteAddress": "1.152.111.246",
18-
"body": Buffer.alloc(0),
19-
"ssl": true,
22+
"payload": Buffer.alloc(0),
2023
"headers": {
2124
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
2225
"accept-language": "en-US,en;q=0.9,pl-PL;q=0.8,pl;q=0.7,ru;q=0.6",
@@ -45,10 +48,13 @@ describe('eventToRequestOptions', () => {
4548
const reqOpts = eventToRequestOptions(eventHttpApiV1);
4649
expect(reqOpts).toEqual({
4750
"method": "GET",
48-
"path": "/inspect?param=ab%20cd",
51+
"path": {
52+
pathname: "/inspect",
53+
protocol: 'https',
54+
query: {"param": "ab cd"},
55+
},
4956
"remoteAddress": "9.9.9.9",
50-
"body": Buffer.alloc(0),
51-
"ssl": true,
57+
"payload": Buffer.alloc(0),
5258
"headers": {
5359
"content-length": "0",
5460
"host": "apiid.execute-api.ap-southeast-2.amazonaws.com",
@@ -74,10 +80,13 @@ describe('eventToRequestOptions', () => {
7480
const reqOpts = eventToRequestOptions(eventHttpApiV2);
7581
expect(reqOpts).toEqual({
7682
"method": "GET",
77-
"path": "/inspect?param=ab%20cd",
83+
"path": {
84+
pathname: "/inspect",
85+
protocol: 'https',
86+
query: {"param": "ab cd"},
87+
},
7888
"remoteAddress": "9.9.9.9",
79-
"body": Buffer.alloc(0),
80-
"ssl": true,
89+
"payload": Buffer.alloc(0),
8190
"headers": {
8291
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
8392
"accept-encoding": "gzip, deflate, br",
@@ -104,10 +113,13 @@ describe('eventToRequestOptions', () => {
104113
const reqOpts = eventToRequestOptions(eventHttpApiLegacy);
105114
expect(reqOpts).toEqual({
106115
"method": "GET",
107-
"path": "/inspect?param=ab%20cd",
116+
"path": {
117+
pathname: "/inspect",
118+
protocol: 'https',
119+
query: {"param": "ab cd"},
120+
},
108121
"remoteAddress": "9.9.9.9",
109-
"body": Buffer.alloc(0),
110-
"ssl": true,
122+
"payload": Buffer.alloc(0),
111123
"headers": {
112124
"content-length": "0",
113125
"host": "apiid.execute-api.ap-southeast-2.amazonaws.com",
@@ -126,10 +138,13 @@ describe('eventToRequestOptions', () => {
126138
const reqOpts = eventToRequestOptions(eventAlb);
127139
expect(reqOpts).toEqual({
128140
"method": "GET",
129-
"path": "/inspect?param=ab%20cd",
141+
"path": {
142+
pathname: "/inspect",
143+
protocol: 'http',
144+
query: {"param": "ab cd"},
145+
},
130146
"remoteAddress": "1.136.104.131",
131-
"body": Buffer.alloc(0),
132-
"ssl": false,
147+
"payload": Buffer.alloc(0),
133148
"headers": {
134149
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
135150
"accept-language": "en-US,en;q=0.9,pl-PL;q=0.8,pl;q=0.7,ru;q=0.6",
@@ -148,10 +163,15 @@ describe('eventToRequestOptions', () => {
148163
const reqOpts = eventToRequestOptions(evenMultiHeadertAlb);
149164
expect(reqOpts).toEqual({
150165
"method": "GET",
151-
"path": "/inspect?param=ab%20cd",
166+
"path": {
167+
pathname: "/inspect",
168+
protocol: 'http',
169+
query: {
170+
"param": "ab cd",
171+
},
172+
},
152173
"remoteAddress": "1.136.104.131",
153-
"body": Buffer.alloc(0),
154-
"ssl": false,
174+
"payload": Buffer.alloc(0),
155175
"headers": {
156176
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
157177
"accept-language": "en-US,en;q=0.9,pl-PL;q=0.8,pl;q=0.7,ru;q=0.6",
@@ -191,10 +211,13 @@ describe('eventToRequestOptions', () => {
191211
});
192212
expect(reqOpts).toEqual({
193213
"method": "HEAD",
194-
"path": "/",
214+
"path": {
215+
pathname: "/",
216+
protocol: 'http',
217+
query: {},
218+
},
195219
"remoteAddress": '129.45.45.48',
196-
"body": Buffer.alloc(0),
197-
"ssl": false,
220+
"payload": Buffer.alloc(0),
198221
"headers": {
199222
"x-forwarded-for": "10.10.2.3",
200223
"x-forwarded-proto": "http",
@@ -223,10 +246,13 @@ describe('eventToRequestOptions', () => {
223246

224247
expect(reqOpts).toEqual({
225248
"method": "HEAD",
226-
"path": "/",
249+
"path": {
250+
pathname: "/",
251+
protocol: 'https',
252+
query: {},
253+
},
227254
"remoteAddress": '129.45.45.48',
228-
"body": Buffer.alloc(0),
229-
"ssl": true,
255+
"payload": Buffer.alloc(0),
230256
"headers": {
231257
},
232258
})
@@ -236,10 +262,13 @@ describe('eventToRequestOptions', () => {
236262
const reqOpts = eventToRequestOptions(eventHealth);
237263
expect(reqOpts).toEqual({
238264
"method": "HEAD",
239-
"path": "/",
265+
"path": {
266+
pathname: "/",
267+
protocol: 'http',
268+
query: {},
269+
},
240270
"remoteAddress": undefined,
241-
"body": Buffer.alloc(0),
242-
"ssl": false,
271+
"payload": Buffer.alloc(0),
243272
"headers": {
244273
"user-agent": "ELB-HealthChecker/2.0",
245274
},

0 commit comments

Comments
 (0)