UNPKG

@bitblit/epsilon

Version:

Tiny adapter to simplify building API gateway Lambda APIS

168 lines 7.49 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ResponseUtil = void 0; const common_1 = require("@bitblit/ratchet/common"); const zlib_1 = __importDefault(require("zlib")); class ResponseUtil { // Prevent instantiation // eslint-disable-next-line @typescript-eslint/no-empty-function constructor() { } 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; } // No wrapped error since its already copied 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) { common_1.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]; // TODO: make sure not double encoding 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, }, }; } // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types 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') { // Do Nothing } else if (Buffer.isBuffer(input.body)) { rval.body = input.body.toString('base64'); rval.headers = input.headers || {}; rval.headers['Content-Type'] = input.body.contentType; // TODO: Does this work? rval.isBase64Encoded = true; } } else { // Its a generic object 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 { // boolean , number, etc - other top level types // See : https://stackoverflow.com/questions/18419428/what-is-the-minimum-valid-json 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 applyGzipIfPossible(encodingHeader, proxyResult) { return __awaiter(this, void 0, void 0, function* () { const rval = proxyResult; if (encodingHeader && encodingHeader.toLowerCase().indexOf('gzip') > -1) { const bigEnough = proxyResult.body.length > 1400; // MTU packet is 1400 bytes let contentType = common_1.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 = yield this.gzip(asBuffer); common_1.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 { common_1.Logger.silly('Not gzipping, too small or exempt content'); } } else { common_1.Logger.silly('Not gzipping, not an accepted encoding'); } return rval; }); } static gzip(input) { const promise = new Promise(function (resolve, reject) { zlib_1.default.gzip(input, function (error, result) { if (!error) resolve(result); else reject(error); }); }); return promise; } } exports.ResponseUtil = ResponseUtil; //# sourceMappingURL=response-util.js.map