uspring
Version:
A very fast Webserver which has interface like springboot
330 lines (329 loc) • 15.3 kB
JavaScript
"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;