UNPKG

@bitblit/ratchet-epsilon-common

Version:

Tiny adapter to simplify building API gateway Lambda APIS

145 lines 5.89 kB
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