UNPKG

rested

Version:

{REST}ed; {REST}ful Enterprise Data-as-a-Service (DaaS)

102 lines (100 loc) 4.07 kB
// __Dependencies__ const from = require('from2'); const mongoose = require('mongoose'); const errors = require('http-errors'); // __Module Definition__ module.exports = function (options, protect) { const rested = require('..'); // A controller property that sets whether errors should be // handled if possible, or just set status code. protect.property('handleErrors', true, handle => handle ? true : false); // If it's a Mongo bad hint error, convert to a bad request error. protect.use((error, request, response, next) => { if (!error) return next(); if (!error.message) return next(error); let message = 'The requested query hint is invalid' // Bad Mongo query hint (2.x). if (error.message === 'bad hint') return next(errors.BadRequest(message)); // Bad Mongo query hint (3.x). if (error.message.match('planner returned error: bad hint')) return next(errors.BadRequest(message)); if (!error.$err) return next(error); // Mongoose 3 if (error.$err.match('planner returned error: bad hint')) return next(errors.BadRequest(message)); next(error); }); // Convert Mongo duplicate key error to an unprocessible entity error protect.use((error, request, response, next) => { if (!error) return next(); if (!error.message) return next(error); if (error.message.indexOf('E11000 duplicate key error') === -1) return next(error); let body = {}; let scrape = /(?:([^\s]+)[_]\d+)?\s+dup key: { : "([^"]+)" }/; let scraped = scrape.exec(error.message) || []; let path = scraped[1] || '???'; let value = scraped[2] || '???'; body[path] = { message: `Path \`${path}\` (${value}) must be unique.`, originalMessage: error.message, name: 'MongoError', path: path, type: 'unique', value: value }; let translatedError = errors.UnprocessableEntity(); translatedError.errors = body; next(translatedError); }); // Convert Mongo validation errors to unprocessable entity errors. protect.use((error, request, response, next) => { if (!error) return next(); if (!(error instanceof mongoose.Error.ValidationError)) return next(error); let newError = errors.UnprocessableEntity(); newError.errors = error.errors; next(newError); }); // Convert Mongoose version conflict error to LockConflict. protect.use((error, request, response, next) => { if (!error) return next(); if (!(error instanceof mongoose.Error.VersionError)) return next(error); next(errors.Conflict()); }); // Translate other errors to internal server errors. protect.use((error, request, response, next) => { if (!error) return next(); if (error instanceof Error && !isNaN(error.status)) return next(error); let error2 = errors.InternalServerError(error.message); error2.stack = error.stack; next(error2); }); // Format the error based on the Accept header. protect.use((error, request, response, next) => { if (!error) return next(); // Always set the status code if available. if (error.status >= 100) response.status(error.status); if (!this.handleErrors()) return next(error); rested.formatters(response, (error2, formatter) => { if (error2) return next(error2); let errors = error.errors || [error]; if (!Array.isArray(errors)) errors = Object.keys(errors).map(key => errors[key]); errors = errors.map(err => { let o = {}; Object.getOwnPropertyNames(err).forEach(key => o[key] = err[key]); if (o.stack) o.stack = o.stack.trim(); delete o.domainEmitter; delete o.domainThrown; delete o.domain; return o; }); // Always send as single error errors = [errors.shift() || error, null]; let f = formatter(false); f.on('error', next); from.obj((size, next) => next(null, errors.shift())).pipe(f).pipe(response); }); }); };