UNPKG

celeritas

Version:

This is an API service framework which supports API requests over HTTP & WebSockets.

139 lines (110 loc) 4.55 kB
'use strict'; const uuid = require("uuid"); const querystring = require('querystring'); const validator = require('validator'); const zlib = require('zlib'); const { promisify } = require('util'); const lodash = require('lodash'); const gzipAsync = promisify(zlib.gzip); String.prototype.capitalize = function() { return this.replace(/(?:^|\s)\S/g, function(a) { return a.toUpperCase(); }); }; class HttpCall { constructor (app, request, response, util) { var ipAddress = request.headers['x-forwarded-for'] || request.connection.remoteAddress; if (ipAddress.indexOf(",") !== -1) ipAddress = ipAddress.split(",")[0]; var queryData = (request.url.indexOf("?") !== -1) ? querystring.parse(request.url.substring(request.url.indexOf("?")+1)) : {}; if (typeof queryData.ipAddress == "undefined") queryData.ipAddress = ipAddress; for (let param in queryData) { try { queryData[param] = JSON.parse(queryData[param]); } catch (err) {} } Object.assign(this, { id: uuid().replace(/-/g, ""), status: util.PENDING, method: request.method.toUpperCase(), hostname: request.headers.host, url: request.headers.host + request.url, route: request.url.split("?").shift().substring(1).toLowerCase(), post: null, get: queryData, param: request.url.split("?").shift().substring(1).split("/").pop(), timestamp: new Date().toISOString(), ipAddress: ipAddress, returnMimeType: "application/json", returnInput: (typeof request.headers['x-return-input'] !== "undefined" && JSON.parse(request.headers['x-return-input']) == true) ? true : false, compression: { input: (typeof request.headers['content-encoding'] !== "undefined" && (request.headers['content-encoding'].indexOf("gzip") > -1)) ? "gzip" : null, output: (typeof request.headers['accept-encoding'] !== "undefined" && (request.headers['accept-encoding'].indexOf("gzip") > -1)) ? "gzip" : null }, cache: util.assembleCache(request.headers['cache-control'] || ""), paging: util.assemblePaging(queryData), sort: util.assembleSort(queryData), auth: util.assembleAuth(request.headers.authorization), output: { code: null, data: null } }); this._rawGet = lodash.cloneDeep(this.get); if (validator.isMongoId(this.param)) this.route = (this.route.substr(0, this.route.length - this.param.length)) + "*"; else this.param = null; request.setTimeout((typeof request.headers['x-timeout'] !== "undefined") ? parseInt(request.headers['x-timeout']) : app.api.timeout); this.request = request; this.response = response; } static async emit (call) { var pkge = require("./../package.json"); if (call.output.code >= 400 && typeof call.output.data == "object") call.returnMimeType = "application/json"; var headers = { "Access-Control-Expose-Headers": call.app.accessControl.exposeHeaders, "Access-Control-Allow-Headers": call.app.accessControl.allowHeaders, "Access-Control-Allow-Origin": call.app.accessControl.allowOrigin, "Access-Control-Allow-Methods": call.app.accessControl.allowMethods, "Access-Control-Allow-Credentials": true, "X-Request-Id": call.id, "X-Powered-By": pkge.name + "@" + pkge.version, "Content-Type": call.returnMimeType, "Authorization": (call.auth !== null && (call.auth.authenticated == true || call.output.code != 401)) ? call.auth.type.capitalize() + " " + call.auth.raw : null }; if (call.output.code >= 300 && call.output.code < 400 && call.output.data.result.redirect) headers.Location = call.output.data.result.redirect; if (call.compression.output && call.compression.output.indexOf("gzip") >= 0) { headers['Content-Encoding'] = "gzip"; headers['Accept-Encoding'] = "gzip"; } call.response.writeHead(call.output.code, headers); if (call.output.code != 204) { var emit = call.output.data; if (call.app.api.metaData !== true) emit = emit.error ? emit.error : emit.result; switch (call.returnMimeType) { case "application/json": emit = JSON.stringify(emit); break; default: emit = typeof emit !== "string" ? emit.toString() : emit; } if (call.compression.output === "gzip") { const gzip = zlib.createGzip(); gzip.pipe(call.response); gzip.end(emit); } else { call.response.end(emit || ""); } } else { call.response.end(); } if (call.output.code < 300) call.status = call.util.COMPLETE; else call.status = call.util.ERROR; delete call.app._calls[call.id]; return Promise.resolve(call); } } module.exports = HttpCall;