@bitblit/ratchet-epsilon-common
Version:
Tiny adapter to simplify building API gateway Lambda APIS
145 lines • 5.89 kB
JavaScript
import { Logger } from '@bitblit/ratchet-common/logger/logger';
import { MapRatchet } from '@bitblit/ratchet-common/lang/map-ratchet';
import zlib from 'zlib';
export class ResponseUtil {
constructor() { }
static decodeUriComponentAndReplacePlus(val) {
return decodeURIComponent(val.replace(/\+/g, ' '));
}
static errorResponse(err) {
const body = {
errors: err.errors,
httpStatusCode: err.httpStatusCode,
requestId: err.requestId,
};
if (err.detailErrorCode) {
body['detailErrorCode'] = err.detailErrorCode;
}
if (err.endUserErrors && err.endUserErrors.length > 0) {
body['endUserErrors'] = err.endUserErrors;
}
if (err.details) {
body['details'] = err.details;
}
if (err.wrappedError) {
body['wrappedError'] = err.wrappedError.name + ' : ' + err.wrappedError.message;
}
const errorResponse = {
statusCode: err.httpStatusCode,
isBase64Encoded: false,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
};
return errorResponse;
}
static redirect(target, code = 301, queryParams = null) {
if (code !== 301 && code !== 302 && code !== 307) {
throw new Error('Code must be 301 or 302 or 307 for a redirect');
}
let redirectTarget = target;
if (queryParams) {
const keys = Object.keys(queryParams);
if (keys.length > 0) {
Logger.silly('Applying params to input target : %j', queryParams);
redirectTarget += redirectTarget.indexOf('?') === -1 ? '?' : '&';
for (let i = 0; i < keys.length; i++) {
const k = keys[i];
redirectTarget += k + '=' + encodeURIComponent(queryParams[k]);
if (i < keys.length - 1) {
redirectTarget += '&';
}
}
}
}
return {
statusCode: code,
body: '{"redirect-target":"' + redirectTarget + '}',
headers: {
'Content-Type': 'application/json',
Location: redirectTarget,
},
};
}
static coerceToProxyResult(input) {
let rval = null;
if (input != null) {
if (typeof input === 'object') {
if (input.statusCode && input.body !== undefined) {
rval = Object.assign({}, input);
if (typeof input.body === 'string') {
}
else if (Buffer.isBuffer(input.body)) {
rval.body = input.body.toString('base64');
rval.headers = input.headers || {};
rval.headers['Content-Type'] = input.body.contentType;
rval.isBase64Encoded = true;
}
}
else {
const headers = input.headers || {};
headers['Content-Type'] = 'application/json';
rval = ResponseUtil.coerceToProxyResult({
statusCode: 200,
body: JSON.stringify(input),
headers: headers,
isBase64Encoded: false,
});
}
}
else if (typeof input === 'string' || Buffer.isBuffer(input)) {
rval = ResponseUtil.coerceToProxyResult({ statusCode: 200, body: input });
}
else {
const headers = input.headers || {};
headers['Content-Type'] = 'application/json';
rval = ResponseUtil.coerceToProxyResult({
statusCode: 200,
body: JSON.stringify(input),
headers: headers,
isBase64Encoded: false,
});
}
}
return rval;
}
static async applyGzipIfPossible(encodingHeader, proxyResult) {
const rval = proxyResult;
if (encodingHeader && encodingHeader.toLowerCase().indexOf('gzip') > -1) {
const bigEnough = proxyResult.body.length > 1400;
let contentType = MapRatchet.extractValueFromMapIgnoreCase(proxyResult.headers, 'content-type') || '';
contentType = contentType.toLowerCase();
const exemptContent = contentType === 'application/pdf' || contentType === 'application/zip' || contentType.startsWith('image/');
if (bigEnough && !exemptContent) {
const asBuffer = proxyResult.isBase64Encoded ? Buffer.from(proxyResult.body, 'base64') : Buffer.from(proxyResult.body);
const zipped = await this.gzip(asBuffer);
Logger.debug('Comp from %s to %d bytes', asBuffer.length, zipped.length);
const zipped64 = zipped.toString('base64');
rval.body = zipped64;
rval.isBase64Encoded = true;
rval.headers = rval.headers || {};
rval.headers['Content-Encoding'] = 'gzip';
}
else {
Logger.silly('Not gzipping, too small or exempt content');
}
}
else {
Logger.silly('Not gzipping, not an accepted encoding');
}
return rval;
}
static gzip(input) {
const promise = new Promise(function (resolve, reject) {
zlib.gzip(input, function (error, result) {
if (!error)
resolve(result);
else
reject(error);
});
});
return promise;
}
}
//# sourceMappingURL=response-util.js.map