Skip to content

Commit 143156b

Browse files
committed
Merge branch 'luka/lambda-helper-refactor'
2 parents b9b62eb + 79c6e5d commit 143156b

File tree

5 files changed

+139
-127
lines changed

5 files changed

+139
-127
lines changed

.releases/4.59.0.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
**New Features**
2+
3+
* Added `LambdaHelper.processAsync` function (for use with newer AWS Lambda function signature which omits `callback` argument).
4+
5+
**Other**
6+
7+
* Refactored classes related to AWS Lambda functions to use `async/await` pattern (as appropriate).

aws/lambda/LambdaHelper.js

Lines changed: 69 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ module.exports = (() => {
3232
* Configures and returns a log4js logger.
3333
*
3434
* @public
35-
* @param {Object|String=} configuration - Configuration path (as string) or a configuration data (as object).
35+
* @static
36+
* @param {Object|String=} configuration - Configuration path (as string) or configuration data (as an object).
3637
* @returns {Object}
3738
*/
3839
static getLogger(configuration) {
@@ -62,6 +63,7 @@ module.exports = (() => {
6263
* Returns secret value from AWS Secrets Manager.
6364
*
6465
* @public
66+
* @static
6567
* @async
6668
* @param {String} secretId
6769
* @return {Promise<String>}
@@ -74,6 +76,7 @@ module.exports = (() => {
7476
* Builds and returns a new {@link LambdaEventParser}.
7577
*
7678
* @public
79+
* @static
7780
* @param {Object} event
7881
* @returns {LambdaEventParser}
7982
*/
@@ -85,6 +88,7 @@ module.exports = (() => {
8588
* Builds and returns a new {@link LambdaValidator}.
8689
*
8790
* @public
91+
* @static
8892
* @returns {LambdaValidator}
8993
*/
9094
static getValidator() {
@@ -95,6 +99,7 @@ module.exports = (() => {
9599
* Builds and returns a new {@link LambdaResponder}.
96100
*
97101
* @public
102+
* @static
98103
* @param {Function} callback
99104
* @returns {LambdaResponder}
100105
*/
@@ -106,6 +111,7 @@ module.exports = (() => {
106111
* Builds and returns a new {@link LambdaStage}.
107112
*
108113
* @public
114+
* @static
109115
* @param {String} stage
110116
* @returns {LambdaStage}
111117
*/
@@ -120,83 +126,90 @@ module.exports = (() => {
120126
* the processor, and responding with the processor's result.
121127
*
122128
* @public
129+
* @static
123130
* @async
124131
* @param {String} description - Human-readable description of the Lambda Function.
125132
* @param {Object} event - The actual "event" object passed to the Lambda Function by the AWS framework.
126133
* @param {Function} callback - The actual "callback" function passed to the Lambda Function by the AWS framework.
127134
* @param {Callbacks.LambdaProcessorCallback} processor - The processor that is invoked to perform the work.
128-
* @returns {Promise}
135+
* @returns {Promise<*>}
129136
*/
130137
static async process(description, event, callback, processor) {
131138
const context = { };
132139

133-
return Promise.resolve(context)
134-
.then((context) => {
135-
assert.argumentIsRequired(description, 'description', String);
136-
assert.argumentIsRequired(processor, 'processor', Function);
140+
try {
141+
assert.argumentIsRequired(description, 'description', String);
142+
assert.argumentIsRequired(processor, 'processor', Function);
137143

138-
context.parser = LambdaHelper.getEventParser(event);
139-
context.responder = LambdaHelper.getResponder(callback);
144+
context.parser = LambdaHelper.getEventParser(event);
145+
context.responder = LambdaHelper.getResponder(callback);
140146

141-
if (context.parser.plainText) {
142-
context.responder.setPlainText();
143-
}
147+
if (context.parser.plainText) {
148+
context.responder.setPlainText();
149+
}
144150

145-
if (eventLogger && eventLogger.isTraceEnabled()) {
146-
eventLogger.trace(JSON.stringify(event, null, 2));
147-
}
151+
if (eventLogger && eventLogger.isTraceEnabled()) {
152+
eventLogger.trace(JSON.stringify(event, null, 2));
153+
}
148154

149-
return context;
150-
}).then((context) => {
151-
const validator = LambdaHelper.getValidator();
152-
153-
return validator.validate(event)
154-
.then((valid) => {
155-
if (valid) {
156-
return Promise.resolve(context);
157-
} else {
158-
return Promise.reject(FailureReason.from(LambdaFailureType.LAMBDA_INVOCATION_SUPPRESSED));
159-
}
160-
});
161-
}).then((context) => {
162-
return Promise.resolve()
163-
.then(() => {
164-
return processor(context.parser, context.responder);
165-
}).then((response) => {
166-
context.responder.send(response);
167-
});
168-
}).catch((e) => {
169-
let reason;
170-
171-
if (e instanceof FailureReason) {
172-
reason = e;
173-
174-
if (lambdaLogger) {
175-
if (reason.getIsSevere()) {
176-
lambdaLogger.error(reason.format());
177-
} else {
178-
lambdaLogger.warn(reason.format());
179-
}
180-
}
181-
} else {
182-
reason = new FailureReason({ endpoint: { description }});
183-
reason = reason.addItem(FailureType.REQUEST_GENERAL_FAILURE);
155+
const validator = LambdaHelper.getValidator();
156+
const valid = await validator.validate(event);
157+
158+
if (!valid) {
159+
throw FailureReason.from(LambdaFailureType.LAMBDA_INVOCATION_SUPPRESSED);
160+
}
161+
162+
const response = await processor(context.parser, context.responder);
163+
164+
return await context.responder.send(response);
165+
} catch (e) {
166+
let reason;
184167

185-
if (lambdaLogger) {
186-
lambdaLogger.error(e);
168+
if (e instanceof FailureReason) {
169+
reason = e;
170+
171+
if (lambdaLogger) {
172+
if (reason.getIsSevere()) {
173+
lambdaLogger.error(reason.format());
174+
} else {
175+
lambdaLogger.warn(reason.format());
187176
}
188177
}
178+
} else {
179+
reason = new FailureReason({ endpoint: { description } });
180+
reason = reason.addItem(FailureType.REQUEST_GENERAL_FAILURE);
189181

190-
if (eventLogger && !eventLogger.isTraceEnabled()) {
191-
eventLogger.warn(JSON.stringify(event, null, 2));
182+
if (lambdaLogger) {
183+
lambdaLogger.error(e);
192184
}
185+
}
186+
187+
if (eventLogger && !eventLogger.isTraceEnabled()) {
188+
eventLogger.warn(JSON.stringify(event, null, 2));
189+
}
190+
191+
return await context.responder.sendError(reason, reason.getErrorCode());
192+
}
193+
}
193194

194-
context.responder.sendError(reason, reason.getErrorCode());
195-
});
195+
/**
196+
* Starts a promise chain for the Lambda function, invoking the suppressor, then
197+
* the processor, and responding with the processor's result.
198+
*
199+
* @public
200+
* @static
201+
* @async
202+
* @param {String} description - Human-readable description of the Lambda Function.
203+
* @param {Object} event - The actual "event" object passed to the Lambda Function by the AWS framework.
204+
* @param {Callbacks.LambdaProcessorCallback} processor - The processor that is invoked to perform the work.
205+
* @returns {Promise<*>}
206+
*/
207+
static async processAsync(description, event, processor) {
208+
return LambdaHelper.process(description, event, () => { }, processor);
196209
}
197210

198211
toString() {
199-
return 'LambdaHelper';
212+
return '[ LambdaHelper ]';
200213
}
201214
}
202215

aws/lambda/LambdaResponder.js

Lines changed: 36 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ module.exports = (() => {
9090
* Adds multiple {@link LambdaResponseGenerator} instances.
9191
*
9292
* @public
93-
* @param {Array<LambdaResponseGenerator>} strategies
93+
* @param {Array<LambdaResponseGenerator>} generators
9494
* @returns {LambdaResponder}
9595
*/
9696
addResponseGenerators(generators) {
@@ -103,13 +103,14 @@ module.exports = (() => {
103103
* Immediately transmits an error response.
104104
*
105105
* @public
106+
* @async
106107
* @param {Object|String} response
107108
* @param {Number=} responseCode
108-
* @returns {Promise}
109+
* @returns {Promise<*>}
109110
*/
110-
sendError(response, responseCode) {
111+
async sendError(response, responseCode) {
111112
if (this.complete) {
112-
return Promise.resolve(null);
113+
return null;
113114
}
114115

115116
if (is.string(response)) {
@@ -123,65 +124,56 @@ module.exports = (() => {
123124
* Immediately transmits a successful response.
124125
*
125126
* @public
127+
* @async
126128
* @param {Object|String} response
127129
* @param {Number=} responseCode
128-
* @returns {Promise}
130+
* @returns {Promise<*>}
129131
*/
130-
send(response, responseCode) {
132+
async send(response, responseCode) {
131133
if (this.complete) {
132-
return Promise.resolve(null);
134+
return null;
133135
}
134136

135137
this._complete = true;
136138

137-
let responsePromise = null;
139+
let transformed;
138140

139-
if (responsePromise === null && (is.null(response) || is.undefined(response))) {
140-
responsePromise = Promise.resolve()
141-
.then(() => {
142-
return LambdaResponseGenerator.buildResponseForApiGateway(responseCode || 200, this.headers, response);
143-
});
144-
}
145-
146-
if (responsePromise === null) {
147-
responsePromise = Promise.resolve()
148-
.then(() => {
149-
let serialized;
141+
if (!is.null(response) && !is.undefined(response)) {
142+
let serialized;
150143

151-
if (Buffer.isBuffer(response)) {
152-
serialized = response;
153-
} else if (is.object(response)) {
154-
serialized = JSON.stringify(response);
155-
} else {
156-
this.setHeader('Content-Type', 'text/plain');
144+
if (Buffer.isBuffer(response)) {
145+
serialized = response;
146+
} else if (is.object(response)) {
147+
serialized = JSON.stringify(response);
148+
} else {
149+
this.setHeader('Content-Type', 'text/plain');
150+
serialized = response.toString();
151+
}
157152

158-
serialized = response.toString();
159-
}
160-
161-
return this._processor.process(responseCode || 200, this.headers, serialized);
162-
});
153+
transformed = await this._processor.process(responseCode || 200, this.headers, serialized);
154+
} else {
155+
transformed = LambdaResponseGenerator.buildResponseForApiGateway(responseCode || 200, this.headers, response);
163156
}
164157

165-
return responsePromise.then((response) => {
166-
this._callback(null, response);
158+
this._callback(null, transformed);
167159

168-
return response;
169-
});
160+
return transformed;
170161
}
171162

172163
/**
173164
* Immediately transmits a base-64 encoded response.
174165
*
175166
* @public
167+
* @async
176168
* @param {Buffer} buffer
177169
* @param {String=} contentType
178-
* @returns {Promise}
170+
* @returns {Promise<*>}
179171
*/
180-
sendBinary(buffer, contentType) {
172+
async sendBinary(buffer, contentType) {
181173
assert.argumentIsOptional(contentType, 'contentType', String);
182174

183175
if (this.complete) {
184-
return Promise.resolve(null);
176+
return null;
185177
}
186178

187179
this._complete = true;
@@ -191,31 +183,33 @@ module.exports = (() => {
191183
}
192184

193185
const response = LambdaResponseGenerator.buildResponseForApiGateway(200, this.headers, buffer.toString('base64'));
186+
194187
response.isBase64Encoded = true;
195188

196189
this._callback(null, response);
197190

198-
return Promise.resolve(response);
191+
return response;
199192
}
200193

201194
/**
202195
* Immediately transmits an ad hoc response.
203196
*
204197
* @public
198+
* @async
205199
* @param {*} response
206200
* @param {*=} error
207-
* @returns {Promise}
201+
* @returns {Promise<*>}
208202
*/
209-
sendRaw(response, error) {
203+
async sendRaw(response, error) {
210204
if (this.complete) {
211-
return Promise.resolve(null);
205+
return null;
212206
}
213207

214208
this._complete = true;
215209

216210
this._callback(error || null, response);
217211

218-
return Promise.resolve(response);
212+
return response;
219213
}
220214

221215
toString() {

aws/lambda/responses/LambdaResponseGenerator.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@ module.exports = (() => {
2727
* Processes the response data and returns a response object (or a null value).
2828
*
2929
* @public
30+
* @async
3031
* @param {Number} responseCode
3132
* @param {Object} responseHeaders
3233
* @param {Buffer|String} responseData
3334
* @param {Number} responseSize
3435
* @returns {Promise<Object|null>}
3536
*/
36-
generate(responseCode, responseHeaders, responseData, responseSize) {
37+
async generate(responseCode, responseHeaders, responseData, responseSize) {
3738
return Promise.resolve()
3839
.then(() => {
3940
return this._generate(responseCode, responseHeaders, responseData, responseSize);

0 commit comments

Comments
 (0)