I want to server a error.ejs file for all errors that are not handled individually.
This code does not do anything when I get a duplicate key error from mongoose user.save()
http://expressjs.com/guide.html#error-handling
app.js
app.use(function(err, req, res, next){
res.status(500);
res.render('error', { error: "Woops, we encountered an error..." });
});
routes/index.js
user.save(function(err){
if ( err ) throw err;
});
The example below gives me this error: Caught exception: [ReferenceError: next is not defined]
user.save(function(err){
if ( err ) next(err);
});
Your snippet
user.save(function(err){
if ( err ) next(err);
});
is presumably inside a route that has a function( req, res ) on it?
What you need to do is a "next" on that function
function MyRoute( req, res, next ) {
user.save(function(err){
if ( err )
return next(err);
// carry on here doing whatever
});
}
app.get('/some/route', MyRoute);
Related
So I have this error handler middleware
class ErrorHandler extends Error {
constructor(statusCode, message) {
super();
this.statusCode = statusCode;
this.message = message;
}
}
const handleError = (err, res) => {
const { statusCode, message } = err;
res.status(statusCode).json({
status: "error",
statusCode,
message: "resource not found"
});
};
module.exports = {
ErrorHandler,
handleError
}
calling it in index.js
app.use((err, req, res, next) => {
handleError(err, res);
})
And I want to use it in all my methods, but I cant figure it out how to use it with catch. it does not seem very clear for me. For the 404 error works just fine, but If I'm trying to throw a 500 error, e.g. a ReferenceError I dont know how to use my function.
exports.getAll = function(req, res, next) {
User.find({})
.exec()
.then(users => {
if (users.length === 0) {
throw new ErrorHandler(404, "No users found");
} else {
res.json(users);
next;
}
})
.catch(error => {
res.status(500).send({
message: "Error finding users",
error: error
})
})
};
in .catch I want to use my error handler like I did in .then
in catch block, you can use next to go handle error like with next(err)
.catch(err=>{
let error = new ErrorHandler(500,"Error finding users");
next(error);
})
I am trying to hook into the save function in Mongoose to return an error to the client of a REST API if a certain condition is not met in the schema. I can't use a validator for this as the restriction is calculated over multiple fields of the schema.
I am trying to add a hook in the following style:
mySchema.pre('save', function (next) {
if(condition_is_not_met) {
const err = new Error('Condition was not met');
next(err);
}
next();
});
This throws an error when I try to make a call to the endpoint trying to insert an object that violates the condition checked for in the hook:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent
to the client
I am guessing that this happens because execution continues on the route writing the header to send it to the client.
router.post('/mySchema', returnType, (req, res) => {
const s = new mySchema(req.body);
s.save((err) => {
if (err) {
const msg = { message: 'Could not add', error: err }; // This is returned to the caller
res.status(500);
res.send(msg);
}
res.status(200);
res.send(s);
});
});
How can i fix this issue? I have been searching quite a bit but the topics I found so far do not help me to solve my issue. They only helped me to identify the cause without offering a working solution.
did you try having an else branch for the success response? Since even if the object is invalid the success response will still be executed. Try it like below
router.post("/mySchema", returnType, (req, res) => {
const s = new mySchema(req.body);
s.save(err => {
if (err) {
const msg = { message: "Could not add", error: err };
res.status(500);
res.send(msg);
} else {
res.status(200);
res.send(s);
}
});
});
Pardon my code formatting, I am AFK
If I send a valid fetch api query to this Express server it works fine. If I send an invalid query the server crashes (ReferenceError: next is not defined). How can I change this so that if an error occurs;
the server does not crash
the client receives an error message from the server
Express server.js:
// Add a new test-resource-a
app.post('/test-resource-a', (request, response) => {
pool.query('INSERT INTO my_table SET ?', request.body, (error, result) => {
if (error) {
next(err);
}
response.status(201).send(`test-resource-a added with id: ${result.insertId}`);
});
});
//An error handling middleware
app.use(function (err, req, res, next) {
res.status(500);
res.send("Oops, something went wrong.")
});
This error is mean the next method is not define.
In your case, I think you don't need the next method.
// Add a new test-resource-a
app.post('/test-resource-a', (request, response) => {
pool.query('INSERT INTO my_table SET ?', request.body, (error, result) => {
if (error) {
response.status(400).send(err);
} else {
response.status(201).send(`test-resource-a added with id: ${result.insertId}`);
}
});
});
//An error handling middleware
app.use(function (err, req, res, next) {
res.status(500);
res.send("Oops, something went wrong.")
});
How does the the error handler get triggered?
In sample code, I find that it is placed at the bottom of all the middleware functions. Is the position important?
You can refer below example for some details.
Here, for the '/' GET endpoint a middleware explicitly throws an error 'problem error'.
At this point, express error handler mechanism is triggered and it looks for an error handler (with err as a param). As a result, subsequent 'Hello' is not sent back to the client as its handler is not an error one.
Subsequent error handlers logErrors, clientErrorHandler and errorHandler are invoked one by one to perform relevant tasks with final one writing back the response.
The reason they are placed at the end is to catch the errors thrown by declared middlewares and handle them elegantly i.e. printing it, logging it, sending mails etc. Think of it in terms of a try catch mechanism in other languages like Java. If declared above other middlewares, they would render useless as the errors won't be handled. You can see the difference in output by swapping the order of 'GET' request with the error handlers.
const express = require('express');
const app = express();
app.get('/', (req, res, next) => next(new Error('problem error')), (req, res) => {
res.status(200).send("Hello");
});
app.use(logErrors);
app.use(clientErrorHandler);
app.use(errorHandler);
function logErrors (err, req, res, next) {
console.error(err.stack)
next(err)
}
function clientErrorHandler (err, req, res, next) {
if (req.xhr) {
res.status(500).send({ error: 'Something failed!' })
} else {
next(err)
}
}
function errorHandler (err, req, res, next) {
if (res.headersSent) {
return next(err)
}
res.status(500)
res.render('error', { error: err })
}
app.listen(3000, () => console.log('Example app listening on port 3000!'))
I am trying to shorten my Express/Connect middleware pipeline by only calling certain middleware functions based on the requested path.
However, the following will fail:
_cookieParser(req, res, function(err) {
if(err) return next(err);
_session(req, res, function(err) {
if(err) return next(err);
_csrf(req, res, function(err) {
if(err) return next(err);
loadUserFromSession(req, res, function(err) {
if(err) return next(err);
if(req.method == "POST") {
_bodyParser(req, res, next);
} else {
next();
}
});
});
});
});
But this will work fine:
_cookieParser(req, res, function(err) {
if(err) return next(err);
_session(req, res, function(err) {
if(err) return next(err);
_csrf(req, res, function(err) {
if(err) return next(err);
_bodyParser(req, res, function(err) {
if(err) return next(err);
loadUserFromSession(req, res, next);
});
});
});
});
Where loadUserFromSession is:
function loadUserFromSession(req, res, next) {
if(req.session && req.session.userId) {
userFunctions.getUserById(req.session.userId, function(err, user) {
if(err) return next(err);
if(user) {
req.user = user;
return next();
} else {
req.session.destroy();
return next(new Error('Unauthenticated'));
}
});
} else {
return next(new Error('Unauthenticated'));
}
};
Why can I not call bodyParser() after loadUserFromSession()?
EDIT
Sorry for the lack of detail on the failure/unexpected outcome.
If I put bodyParser() or just json() (since the POST content is json) after loadUserFromSession(), the calls never return inside of json(). If I put breakpoints in node inspector on either res.on('data') or res.on('end') neither get tripped.
The source of the json middleware is below:
exports = module.exports = function(options){
var options = options || {}
, strict = options.strict !== false;
var limit = options.limit
? _limit(options.limit)
: noop;
return function json(req, res, next) {
if (req._body) return next();
req.body = req.body || {};
if (!utils.hasBody(req)) return next();
// check Content-Type
if ('application/json' != utils.mime(req)) return next();
// flag as parsed
req._body = true;
// parse
limit(req, res, function(err){
if (err) return next(err);
var buf = '';
req.setEncoding('utf8');
req.on('data', function(chunk){
buf += chunk <==BREAKPOINT NEVER GETS CALLED
});
req.on('end', function(){
var first = buf.trim()[0]; <==BREAKPOINT NEVER GETS CALLED
if (0 == buf.length) {
return next(400, 'invalid json, empty body');
}
if (strict && '{' != first && '[' != first) return next(400, 'invalid json');
try {
req.body = JSON.parse(buf, options.reviver);
next();
} catch (err){
err.body = buf;
err.status = 400;
next(err);
}
});
});
}
};
OK, consider this advice/code review as opposed to a specific answer, but hopefully this helps.
First, my guess is understanding the following will solve your problem and unconfuse you, although I can't say exactly why your second example above behaves differently from the first example given your isolated snippets, but do some experiments base on this information: For a given request, the series of events (data, end, etc) will fire once and only once. If a listener is not attached when they fire, that listener never gets called. If a listener gets attached after they fire, it will never get called. The bodyParser has code to avoid attempting to re-parse the same request body more than once (because the necessary events would never fire and the code would hang without responding to the request).
SO, I suspect that in your app you have app.use(express.bodyParser()) and that middleware is getting called and running prior to your custom stuff above. Thus, my suggestion, which also addresses your file upload security question is:
Don't install the bodyParser globally like you see in the examples: app.use(express.bodyParser()). This code is neat for day-1 example apps, but it's totally inappropriate for a production site. You should instead do something like:
app.post('/upload/some/file', express.bodyParser(), myUploadHandler);
And just use the body parser exactly where it's needed and nowhere else. Don't go further down your stack of bizarre nesty middleware. There are clean ways to get the functionality, security, and efficiency you need that work in HARMONY with the middleware stack design built into connect. In general, understand that you can use different middleware stacks on different paths and express/connect can be configured to nicely match what you want to happen on a path-by-path basis.