Skip to content

Commit ff104e1

Browse files
authored
Merge pull request #11 from Moesif/support-event-v2
Support lambda event v2
2 parents 02ddb15 + 2d3700d commit ff104e1

File tree

5 files changed

+276
-35
lines changed

5 files changed

+276
-35
lines changed

lib/index.js

+125-33
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ module.exports = function (options, handler) {
213213
};
214214

215215
moesifMiddleware.startCaptureOutgoing = function() {
216-
console.log('Inside Start capturing');
216+
logMessage(options.debug, 'startCaptureOutgoing', 'initiating outgoing');
217217
if (moesifMiddleware._mo_patch) {
218218
logMessage(
219219
options.debug,
@@ -234,73 +234,165 @@ module.exports = function (options, handler) {
234234
};
235235

236236
function mapResponseHeaders(event, context, result) {
237-
const headers = result.headers || {}; // NOTE: Mutating event.headers; prefer deep clone of event.headers
238-
return headers;
237+
const headers = Object.assign({}, result.headers || {}); // NOTE: Mutating event.headers; prefer deep clone of event.headers
238+
return headers;
239239
}
240240

241-
function logEvent(event, context, err, result, options, moesifController) {
242-
if (!event.httpMethod || !event.headers) {
243-
logMessage(
244-
options.debug,
245-
'logEvent',
246-
'AWS Lambda trigger must be a Load Balancer or API Gateway. ' +
247-
'See https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-set-up-simple-proxy.html#api-gateway-set-up-lambda-proxy-integration-on-proxy-resource'
248-
);
249-
return Promise.resolve();
241+
// in V2
242+
// https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html
243+
// if there is no statusCode but valid JSON, API gateway will interpret
244+
// the response.
245+
function translateLambdaResultIfNeeded(result, isV1) {
246+
if (isV1) {
247+
return result || {};
250248
}
251249

252-
if (options.skip(event, context)) {
253-
// exit early
254-
return Promise.resolve();
250+
if (result && result.statusCode) {
251+
return result;
255252
}
256253

254+
if ((!result || !result.statusCode) && (typeof result === 'object' || typeof result === 'string' || typeof result === 'undefined')) {
255+
return {
256+
isBase64Encoded: false,
257+
statusCode: 200,
258+
body: typeof result === 'undefined' ? undefined : JSON.stringify(result),
259+
headers: {
260+
'content-type': 'application/json'
261+
}
262+
};
263+
}
264+
265+
return result || {};
266+
}
267+
268+
function constructBaseLogData(
269+
event,
270+
context,
271+
err,
272+
result,
273+
options,
274+
isV1
275+
) {
257276
var logData = {};
258277
logData.request = {};
259278
logData.response = {};
260-
logData.request.time =
261-
event && event.requestContext && event.requestContext.requestTimeEpoch
262-
? new Date(event && event.requestContext && event.requestContext.requestTimeEpoch)
263-
: Date.now();
279+
if (isV1) {
280+
logData.request.time =
281+
event && event.requestContext && event.requestContext.requestTimeEpoch
282+
? new Date(event.requestContext.requestTimeEpoch)
283+
: Date.now();
284+
} else {
285+
logData.request.time =
286+
event && event.requestContext && event.requestContext.timeEpoch
287+
? new Date(event.requestContext.timeEpoch)
288+
: Date.now();
289+
}
290+
291+
if (isV1) {
292+
logData.request.uri = getURLWithQueryStringParams(event);
293+
} else {
294+
logData.request.uri =
295+
event.rawPath + (event.rawQueryString ? "?" + event.rawQueryString : "");
296+
}
297+
298+
if (isV1) {
299+
logData.request.verb = event.httpMethod;
300+
} else {
301+
logData.request.verb =
302+
event.requestContext &&
303+
event.requestContext.http &&
304+
event.requestContext.http.method;
305+
}
264306

265-
logData.request.uri = getURLWithQueryStringParams(event);
266-
logData.request.verb = event.httpMethod;
267307
logData.request.apiVerion = options.getApiVersion(event, context);
268-
logData.request.ipAddress =
269-
requestIp.getClientIp(event) ||
270-
(event.requestContext &&
271-
event.requestContext.identity &&
272-
event.requestContext.identity.sourceIp);
273-
logData.request.headers = event.headers || {};
308+
309+
if (isV1) {
310+
logData.request.ipAddress =
311+
requestIp.getClientIp(event) ||
312+
(event.requestContext &&
313+
event.requestContext.identity &&
314+
event.requestContext.identity.sourceIp);
315+
} else {
316+
logData.request.ipAddress =
317+
event.requestContext &&
318+
event.requestContext.http &&
319+
event.requestContext.http.sourceIp;
320+
}
321+
322+
logData.request.headers = Object.assign({}, event.headers || {});
274323
logData.metadata = options.getMetadata(event, context);
275324

276325
if (options.logBody && event.body) {
277326
if (event.isBase64Encoded) {
278327
logData.request.body = event.body;
279-
logData.request.transferEncoding = 'base64';
328+
logData.request.transferEncoding = "base64";
280329
} else {
281330
const bodyWrapper = safeJsonParse(event.body);
282331
logData.request.body = bodyWrapper.body;
283332
logData.request.transferEncoding = bodyWrapper.transferEncoding;
284333
}
285334
}
286335

287-
logMessage(options.debug, 'logEvent', 'created request: \n' + JSON.stringify(logData.request));
288-
var safeRes = result || {};
289-
logData.response.time = Math.max(new Date(logData.request.time).getTime(), Date.now());
290-
logData.response.status = safeRes.statusCode ? parseInt(safeRes.statusCode) : 599;
336+
logMessage(
337+
options.debug,
338+
"logEvent",
339+
"created request: \n" + JSON.stringify(logData.request)
340+
);
341+
342+
var safeRes = translateLambdaResultIfNeeded(result, isV1);
343+
344+
logData.response.time = Math.max(
345+
new Date(logData.request.time).getTime(),
346+
Date.now()
347+
);
348+
logData.response.status = safeRes.statusCode
349+
? parseInt(safeRes.statusCode)
350+
: 599;
291351
logData.response.headers = mapResponseHeaders(event, context, safeRes);
292352

293353
if (options.logBody && safeRes.body) {
294354
if (safeRes.isBase64Encoded) {
295355
logData.response.body = safeRes.body;
296-
logData.response.transferEncoding = 'base64';
356+
logData.response.transferEncoding = "base64";
297357
} else {
298358
const bodyWrapper = safeJsonParse(safeRes.body);
299359
logData.response.body = bodyWrapper.body;
300360
logData.response.transferEncoding = bodyWrapper.transferEncoding;
301361
}
302362
}
303363

364+
return logData;
365+
}
366+
367+
368+
function logEvent(event, context, err, result, options, moesifController) {
369+
// v1 has httpMethod, v2 has requestContext
370+
if ((!event.httpMethod && !event.requestContext) || !event.headers) {
371+
logMessage(
372+
options.debug,
373+
'logEvent',
374+
'AWS Lambda trigger must be a Load Balancer or API Gateway. ' +
375+
'See https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-set-up-simple-proxy.html#api-gateway-set-up-lambda-proxy-integration-on-proxy-resource'
376+
);
377+
return Promise.resolve();
378+
}
379+
380+
if (options.skip(event, context)) {
381+
// exit early
382+
return Promise.resolve();
383+
}
384+
385+
const isV1 = event.version === '1.0';
386+
387+
var logData = constructBaseLogData(
388+
event,
389+
context,
390+
err,
391+
result,
392+
options,
393+
isV1
394+
);
395+
304396
logMessage(options.debug, 'logEvent', 'created data: \n' + JSON.stringify(logData));
305397

306398
logData = options.maskContent(logData);

package-lock.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "moesif-aws-lambda",
3-
"version": "1.3.0",
3+
"version": "1.3.1",
44
"description": "API Monitoring Middleware for AWS Lambda",
55
"main": "lib/index.js",
66
"keywords": [

tests/eventV1.json

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
{
2+
"version": "1.0",
3+
"resource": "/my/path",
4+
"path": "/my/path",
5+
"httpMethod": "GET",
6+
"headers": {
7+
"header1": "value1",
8+
"header2": "value2"
9+
},
10+
"multiValueHeaders": {
11+
"header1": [
12+
"value1"
13+
],
14+
"header2": [
15+
"value1",
16+
"value2"
17+
]
18+
},
19+
"queryStringParameters": {
20+
"parameter1": "value1",
21+
"parameter2": "value"
22+
},
23+
"multiValueQueryStringParameters": {
24+
"parameter1": [
25+
"value1",
26+
"value2"
27+
],
28+
"parameter2": [
29+
"value"
30+
]
31+
},
32+
"requestContext": {
33+
"accountId": "123456789012",
34+
"apiId": "id",
35+
"authorizer": {
36+
"claims": null,
37+
"scopes": null
38+
},
39+
"domainName": "id.execute-api.us-east-1.amazonaws.com",
40+
"domainPrefix": "id",
41+
"extendedRequestId": "request-id",
42+
"httpMethod": "GET",
43+
"identity": {
44+
"accessKey": null,
45+
"accountId": null,
46+
"caller": null,
47+
"cognitoAuthenticationProvider": null,
48+
"cognitoAuthenticationType": null,
49+
"cognitoIdentityId": null,
50+
"cognitoIdentityPoolId": null,
51+
"principalOrgId": null,
52+
"sourceIp": "IP",
53+
"user": null,
54+
"userAgent": "user-agent",
55+
"userArn": null,
56+
"clientCert": {
57+
"clientCertPem": "CERT_CONTENT",
58+
"subjectDN": "www.example.com",
59+
"issuerDN": "Example issuer",
60+
"serialNumber": "a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1",
61+
"validity": {
62+
"notBefore": "May 28 12:30:02 2019 GMT",
63+
"notAfter": "Aug 5 09:36:04 2021 GMT"
64+
}
65+
}
66+
},
67+
"path": "/my/path",
68+
"protocol": "HTTP/1.1",
69+
"requestId": "id=",
70+
"requestTime": "04/Mar/2020:19:15:17 +0000",
71+
"requestTimeEpoch": 1583349317135,
72+
"resourceId": null,
73+
"resourcePath": "/my/path",
74+
"stage": "$default"
75+
},
76+
"pathParameters": null,
77+
"stageVariables": null,
78+
"body": "Hello from Lambda!",
79+
"isBase64Encoded": false
80+
}

tests/eventV2.json

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{
2+
"version": "2.0",
3+
"routeKey": "$default",
4+
"rawPath": "/my/path",
5+
"rawQueryString": "parameter1=value1&parameter1=value2&parameter2=value",
6+
"cookies": [
7+
"cookie1",
8+
"cookie2"
9+
],
10+
"headers": {
11+
"header1": "value1",
12+
"header2": "value1,value2"
13+
},
14+
"queryStringParameters": {
15+
"parameter1": "value1,value2",
16+
"parameter2": "value"
17+
},
18+
"requestContext": {
19+
"accountId": "123456789012",
20+
"apiId": "api-id",
21+
"authentication": {
22+
"clientCert": {
23+
"clientCertPem": "CERT_CONTENT",
24+
"subjectDN": "www.example.com",
25+
"issuerDN": "Example issuer",
26+
"serialNumber": "a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1",
27+
"validity": {
28+
"notBefore": "May 28 12:30:02 2019 GMT",
29+
"notAfter": "Aug 5 09:36:04 2021 GMT"
30+
}
31+
}
32+
},
33+
"authorizer": {
34+
"jwt": {
35+
"claims": {
36+
"claim1": "value1",
37+
"claim2": "value2"
38+
},
39+
"scopes": [
40+
"scope1",
41+
"scope2"
42+
]
43+
}
44+
},
45+
"domainName": "id.execute-api.us-east-1.amazonaws.com",
46+
"domainPrefix": "id",
47+
"http": {
48+
"method": "POST",
49+
"path": "/my/path",
50+
"protocol": "HTTP/1.1",
51+
"sourceIp": "IP",
52+
"userAgent": "agent"
53+
},
54+
"requestId": "id",
55+
"routeKey": "$default",
56+
"stage": "$default",
57+
"time": "12/Mar/2020:19:03:58 +0000",
58+
"timeEpoch": 1583348638390
59+
},
60+
"body": "Hello from Lambda",
61+
"pathParameters": {
62+
"parameter1": "value1"
63+
},
64+
"isBase64Encoded": false,
65+
"stageVariables": {
66+
"stageVariable1": "value1",
67+
"stageVariable2": "value2"
68+
}
69+
}

0 commit comments

Comments
 (0)