UNPKG

uspring

Version:

A very fast Webserver which has interface like springboot

330 lines (329 loc) 15.3 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); var constructObjectFromRefUrl_1 = __importDefault(require("./helper/constructObjectFromRefUrl")); var StripUnknown_1 = __importDefault(require("./helper/StripUnknown")); var Joi = __importStar(require("joi")); var RequestMap = /** @class */ (function () { function RequestMap(route) { this.isRequestMap = true; this._routeDocs = []; this._route = __assign(__assign({}, route), { isRouter: true }); this._routeDocs = []; } RequestMap.prototype.get = function (pathname) { var req = new RequestValidator(this._route, 'get', pathname); return req; }; RequestMap.prototype.post = function (pathname) { return new RequestValidator(this._route, 'post', pathname); }; RequestMap.prototype.put = function (pathname) { return new RequestValidator(this._route, 'put', pathname); }; RequestMap.prototype.delete = function (pathname) { return new RequestValidator(this._route, 'delete', pathname); }; return RequestMap; }()); exports.RequestMap = RequestMap; var RequestBodyOption = /** @class */ (function () { function RequestBodyOption() { } return RequestBodyOption; }()); exports.RequestBodyOption = RequestBodyOption; var RequestValidator = /** @class */ (function () { function RequestValidator(_route, _HttpMethod, pathname) { var _this = this; this._authorizeOption = null; //@ts-ignore this._queryString = {}; this._responseBody = {}; // {valid:boolean, 200: schemaObject} this._prefixError = function () { return "Error on " + _this._HttpMethod.toUpperCase() + ", " + _this._HttpPathName + ". Reason: "; }; this._route = _route; this._HttpMethod = _HttpMethod; this._HttpPathName = pathname; } RequestValidator.prototype._executeAuthorize = function (req) { if (!this._authorizeOption) return true; var _a = this._authorizeOption, validator = _a.validator, type = _a.type; type = type ? type.trim() : 'Basic'; var authorizeToken = req.headers ? req.headers.authorization : null; if (!authorizeToken) return false; var tokenType = type[0].toUpperCase() + type.slice(1) + ' '; if (!authorizeToken.startsWith(tokenType)) return false; return validator(authorizeToken.split(tokenType)[1]); }; RequestValidator.prototype._executeQueryString = function (req) { var errorMessages = []; var result = {}; var queryString = req.query; var objToValidate = {}; if (Object.keys(this._queryString).length <= 0) return { errorMessages: errorMessages, isValid: true, result: result }; // if(!queryString) var schema = Joi.object().keys(this._queryString).unknown(); queryString.split('&').forEach(function (keyValue) { var _a = keyValue.split('='), key = _a[0], value = _a[1]; objToValidate[key] = value; }); var objError = Joi.validate(objToValidate, schema, { abortEarly: false }); if (!objError.error) { return { errorMessages: errorMessages, isValid: true, result: objToValidate }; } errorMessages = objError.error.details.map(function (err) { var message = err.message.split(" ").slice(1).join(" "); var path = err.path; return path + " " + message; }); return { errorMessages: errorMessages, isValid: false, result: result }; }; RequestValidator.prototype._executePathVariable = function (req) { var errorMessages = []; var result = {}; if (Object.keys(this._queryString).length <= 0) return { errorMessages: errorMessages, isValid: true, result: result }; var objToValidate = {}; var path = req.url.split('/').slice(1); var objMap = constructObjectFromRefUrl_1.default(this._HttpPathName); var isQueryStringValidating = Object.keys(objMap).length > 0; if (!isQueryStringValidating) { return { isValid: true, errorMessages: [], result: {} }; } Object.keys(this._queryString).forEach(function (pathname) { var position = objMap[pathname]; var value = path[position]; value = value.indexOf('?') ? value.split('?')[0] : value; objToValidate[pathname] = value; }); var schema = Joi.object().keys(this._queryString).unknown(); var objError = Joi.validate(objToValidate, schema, { abortEarly: false }); if (!objError.error) { return { errorMessages: errorMessages, isValid: true, result: objToValidate }; } errorMessages = objError.error.details.map(function (err) { var message = err.message.split(" ").slice(1).join(" "); var path = err.path; return path + " " + message; }); return { errorMessages: errorMessages, isValid: false, result: result }; }; RequestValidator.prototype._executeRequestBody = function (req) { if (!this._requestBody) return { errorMessages: [], isValid: true, result: {} }; var result; var objToValidate = req.body; var schema = this._requestBody.schema; if (schema) result = Joi.validate(objToValidate, schema, { abortEarly: false }); var errorMessages = []; (result.error) && result.error.details.forEach(function (err) { var message = err.message.split(" ").slice(1).join(" "); var pathname = err.path[0]; errorMessages.push(pathname + " " + message); }); var stripUnknownKeys = StripUnknown_1.default.target(schema).value(result.value); var isValid = errorMessages.length === 0; return { errorMessages: errorMessages, isValid: isValid, result: stripUnknownKeys }; }; RequestValidator.prototype._executeResponseBody = function (obj, statusCode) { var schema = this._responseBody[statusCode]; if (!schema) return { isValid: false, objError: { SchemaNotFound: 'No Schema provided for response status ' + statusCode } }; var objError = Joi.validate(obj, schema, { abortEarly: false, stripUnknown: true }); var isValid = objError.error ? false : true; return { isValid: isValid, objError: objError }; }; RequestValidator.prototype._returnResponse = function (res, status, message) { return res.status(status).json({ message: message }); }; RequestValidator.prototype._executeRequestCriteria = function (req) { var errorMessages = []; var queryString = req.url.split('?')[1]; var objToValidate = {}; if (!this._requestCriteria) return { errorMessages: errorMessages, isValid: true, result: {} }; if (!queryString) return { errorMessages: ['No Query String'], isValid: false, result: {} }; var schema = this._requestCriteria.schema; queryString.split('&').forEach(function (keyValue) { var _a = keyValue.split('='), key = _a[0], value = _a[1]; objToValidate[key] = value; }); var result = Joi.validate(objToValidate, schema, { abortEarly: false }); (result.error) && result.error.details.forEach(function (err) { var message = err.message.split(" ").slice(1).join(" "); var pathname = err.path[0]; errorMessages.push(pathname + " " + message); }); var stripUnknownKeys = StripUnknown_1.default.target(schema).value(result.value); var isValid = errorMessages.length === 0; return { errorMessages: errorMessages, isValid: isValid, result: stripUnknownKeys }; }; RequestValidator.prototype.RequestCriteria = function (schema) { var self = this; (function validateRequestBody() { if (!schema) throw new Error(self._prefixError() + 'No schema is provided.'); })(); schema.unknown(); this._requestCriteria = { schema: schema }; return this; }; RequestValidator.prototype.AuthorizeHeader = function (option) { var self = this; (function validateAuthorize() { if (!option) throw new Error(self._prefixError() + " No validator to authorize the token"); })(); var responseMessage = option.responseMessage ? option.responseMessage : 'Not Authorized'; var responseStatus = option.responseStatus ? option.responseMessage : 401; var type = option.type ? option.type : 'jwt'; var validator = option.validator; //token can be accessed in .APPLY this._authorizeOption = { type: type, responseMessage: responseMessage, responseStatus: responseStatus, validator: validator }; return this; }; RequestValidator.prototype.RequestBody = function (option) { var self = this; (function validateRequestBody() { if (!option) throw new Error(self._prefixError() + 'No arguments is provided.'); if (option.valid && !option.schema) throw new Error(self._prefixError() + 'No schema to Validate request body'); })(); this._requestBody = { schema: option.schema }; return this; }; RequestValidator.prototype.RequestHeader = function () { return; }; RequestValidator.prototype.QueryString = function (queryvar, joiValidation) { if (typeof queryvar === 'object' && queryvar.isJoi) { this._queryString['any'] = queryvar; return this; } this._queryString[queryvar] = joiValidation; return this; }; // QueryString(pathvar:string, joiValidation?:Joi.Schema):RequestValidator { // this._queryString[pathvar] = joiValidation; // return this; // } RequestValidator.prototype.ResponseBody = function (obj) { if ("valid" in obj && obj.valid && !obj[200]) throw new Error(this._prefixError() + 'Response need to be validated but no schema'); if (obj) this._responseBody = obj; return this; }; RequestValidator.prototype.Apply = function (callback) { var self = this; var _a = this, _route = _a._route, _HttpMethod = _a._HttpMethod, _HttpPathName = _a._HttpPathName; if (!_route.hasOwnProperty(_HttpMethod)) { _route[_HttpMethod] = {}; } //@ts-ignore _route[_HttpMethod][_HttpPathName] = (function (parent) { return function (req, res) { // this is for Timeout, cut any hang request var futureTimeout = setTimeout(function () { return res.onTimeout(req, res); }, res.timeout); var RESULT = {}; var errorMessages = []; var BAD_PATH_VARIABLE_STATUS = 400; if (!parent._executeAuthorize(req) && parent._authorizeOption) { // if not authorized return 401 return parent._returnResponse(res, parent._authorizeOption.responseStatus, parent._authorizeOption.responseMessage); } var requestParamResult = parent._executePathVariable(req); if (!requestParamResult.isValid) errorMessages = errorMessages.concat(requestParamResult.errorMessages); var queryStringResult = parent._executeQueryString(req); if (!queryStringResult.isValid) errorMessages = errorMessages.concat(queryStringResult.errorMessages); var requestBodyResult = parent._executeRequestBody(req); if (!requestBodyResult.isValid) errorMessages = errorMessages.concat(requestBodyResult.errorMessages); // @ts-ignore var requestCriteriaResult = parent._executeRequestCriteria(req); if (!requestCriteriaResult.isValid) errorMessages = errorMessages.concat(requestBodyResult.errorMessages); if (errorMessages.length > 0) { return parent._returnResponse(res, BAD_PATH_VARIABLE_STATUS, errorMessages); } RESULT = __assign(__assign({}, RESULT), { query: queryStringResult.result, parameters: requestParamResult.result, body: requestBodyResult.result, criteria: requestCriteriaResult.result }); //@ts-ignore res.json = function (obj) { //@ts-ignore if (self._responseBody.valid) { var statusCode = res.statusCode || 200; var _a = self._executeResponseBody(obj, statusCode), isValid = _a.isValid, objError = _a.objError; if (isValid) { return res.json(obj); } return res.status(500).json({ data: objError, message: 'Failed Validation of Response DTO' }); } //no need to validate try { var objString = JSON.stringify(obj); res.writeHeader('Content-Type', "application/json"); if (futureTimeout) clearTimeout(futureTimeout); return res.end(objString); } catch (e) { console.error(e); if (futureTimeout) clearTimeout(futureTimeout); res.writeStatus("500").end(); } }; callback(RESULT, req, res, function (message, err) { if (futureTimeout) clearTimeout(futureTimeout); res.status(500).json({ message: message, err: err }); }); }; }(self)); }; return RequestValidator; }()); exports.RequestValidator = RequestValidator; exports.default = RequestMap;