express-cargo
Version:
express middleware for class-based request parsing
146 lines (145 loc) • 5.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: Object.getOwnPropertyDescriptor(all, name).get
});
}
_export(exports, {
get bindingCargo () {
return bindingCargo;
},
get getCargo () {
return getCargo;
}
});
const _types = require("./types");
const _metadata = require("./metadata");
function getErrorKey(sourceKey, currentKey) {
return sourceKey ? `${sourceKey}.${currentKey}` : currentKey;
}
function bindObject(objectClass, sources, errors, sourceKey = '') {
const metaClass = new _metadata.CargoClassMetadata(objectClass.prototype);
const targetObject = new objectClass();
const fields = metaClass.getFieldList();
const virtualFields = [];
for (const property of fields){
const meta = metaClass.getFieldMetadata(property);
if (!meta) continue;
let value;
const metaKey = meta.getKey();
const key = typeof metaKey === 'string' ? metaKey : metaKey.description;
if (!key) {
errors.push(new _types.CargoFieldError(getErrorKey(sourceKey, key), 'empty string or symbol is not allowed'));
continue;
}
const requestTransformer = meta.getRequestTransformer();
if (requestTransformer) {
try {
value = requestTransformer(sources.req);
} catch (error) {
errors.push(new _types.CargoTransformFieldError(property, `Error while computing request transform field: ${error instanceof Error ? error.message : String(error)}`));
continue;
}
if (value === undefined || value === null) {
if (meta.getOptional()) {
targetObject[property] = null;
} else {
errors.push(new _types.CargoFieldError(getErrorKey(sourceKey, key), `${key} is required`));
}
} else {
targetObject[property] = value;
}
continue;
}
if (meta.getVirtualTransformer()) {
virtualFields.push(property);
continue;
}
const currentSource = meta.getSource();
const currentSourceData = sources[currentSource];
if (currentSourceData) {
value = currentSourceData[key];
}
if (value === undefined || value === null) {
if (meta.getOptional()) {
targetObject[property] = null;
continue;
} else {
errors.push(new _types.CargoFieldError(getErrorKey(sourceKey, key), `${key} is required`));
continue;
}
}
switch(meta.type){
case String:
targetObject[property] = String(value);
break;
case Number:
targetObject[property] = isNaN(Number(value)) ? value : Number(value);
break;
case Boolean:
targetObject[property] = value === true || value === 'true';
break;
case Date:
targetObject[property] = new Date(value);
break;
default:
{
const nextSources = {
...sources,
[currentSource]: value
};
targetObject[property] = bindObject(meta.type, nextSources, errors, getErrorKey(sourceKey, key));
break;
}
}
const transformer = meta.getTransformer();
if (transformer) {
targetObject[property] = transformer(targetObject[property]);
}
for (const rule of meta.getValidators()){
if (!rule.validate(value)) {
errors.push(new _types.CargoFieldError(key, rule.message));
}
}
}
for (const property of virtualFields){
const meta = metaClass.getFieldMetadata(property);
const transformer = meta.getVirtualTransformer();
try {
targetObject[property] = transformer(targetObject);
} catch (error) {
errors.push(new _types.CargoTransformFieldError(property, `Error while computing virtual field: ${error instanceof Error ? error.message : String(error)}`));
}
}
return targetObject;
}
function bindingCargo(cargoClass) {
return (req, res, next)=>{
try {
const errors = [];
const sources = {
req: req,
body: req.body,
query: req.query,
uri: req.params,
header: req.headers,
session: req.session
};
const cargo = bindObject(cargoClass, sources, errors);
if (errors.length > 0) {
throw new _types.CargoValidationError(errors);
}
req._cargo = cargo;
next();
} catch (err) {
next(err);
}
};
}
function getCargo(req) {
return req._cargo;
}