How to throw a 404 error in express.js? - javascript

In app.js, I have
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
so if I request some not exist url like http://localhost/notfound, above code will execute.
In exist url like http://localhost/posts/:postId, I would like to throw 404 error when access some not exist postId or deleted postId.
Posts.findOne({_id: req.params.id, deleted: false}).exec()
.then(function(post) {
if(!post) {
// How to throw a 404 error, so code can jump to above 404 catch?
}

In Express, a 404 isn't classed as an 'error', so to speak - the reasoning behind this is that a 404 isn't usually a sign that's something's gone wrong, it's just that the server couldn't find anything. Your best bet is to explicitly send a 404 in your route handler:
Posts.findOne({_id: req.params.id, deleted: false}).exec()
.then(function(post) {
if(!post) {
res.status(404).send("Not found.");
}
Or alternatively, if this feels like too much repeated code, you could always pull that code out into a function:
function notFound(res) {
res.status(404).send("Not found.");
}
Posts.findOne({_id: req.params.id, deleted: false}).exec()
.then(function(post) {
if(!post) {
notFound(res);
}
I wouldn't recommend using a middleware in this situation solely because I feel like it makes the code less clear - the 404 is the direct result of the database code not finding anything, so it makes sense to have the response in the route handler.

I have the same app.js structure, and I solved this problem in this way in the route handler:
router.get('/something/:postId', function(req, res, next){
// ...
if (!post){
next();
return;
}
res.send('Post exists!'); // display post somehow
});
The next() function will call the next middleware which is the error404 handler if it is right after your routes in the app.js.

You can use this and the end of your routers.
app.use('/', my_router);
....
app.use('/', my_router);
app.use(function(req, res, next) {
res.status(404).render('error/404.html');
});

you're probably looking for something like https://github.com/expressjs/api-error-handler
or just https://github.com/jshttp/http-errors

Even though 404 pages are not considered an error in Express as written here, its really damn handy if you DO handle them like so. For instance when you are developing an API that wants consistent JSON output. The following code should help you with that:
Define a helper function abort to create status errors that can be easily used in your code to pass to the next function:
// Use the `statuses` package which is also a dependency of Express.
const status = require('statuses');
const abort = (code) => {
const err = new Error(status[code]);
const err.status = code;
return err;
};
Define the catch-all middleware for 404 pages which should be defined at the bottom of your stack (after all routes have been added). This forwards the 404 as an error:
app.use((req, res, next) => {
next(abort(404));
});
Lastly, the final error handler will now consistently send all errors in JSON format:
app.use((err, req, res, next) => {
if(!res.headersSent) {
// You can define production mode here so that the stack trace will not be sent.
const isProd = false;
res.status(err.status || 500).json({
error: err.toString(),
...(!isProd && {stack: err.stack.split('\n').map(i => i.trim())}),
});
}
next(err);
});

Related

How to add an error handler in NodeJS after all routes defined by user?

I am writing a library that requires the user to handle errors generated by my library. The way I do it now is that I tell users to add an error handler after all their routes like so:
const app = express();
app.use(MyLibrary.init())
// <user's routes here>
app.use(MyLibrary.errorHandler())
app.use((err, req, res, next) => {
// user's generic error handler
})
The init function in my lib is as follows:
function init() {
return async (request, response, next) => {
try {
// some logic here that modifies the request object and can throw an error
return next(); // this can also throw an error, or generate an unhandled rejection / error
} catch (err) {
next(err);
}
};
}
The errorHandler function is as follows:
function errorHandler() {
return async (err, request, response, next) => {
try {
if (/*err from MyLibrary*/) {
// do something and send a response
return;
}
next(err);
} catch (err) {
next(err);
}
};
}
My aim is to make it so that the user doesn't need to add app.use(MyLibrary.errorHandler()).
One solution that comes to mind is that in the init function, instead of calling next(err), I can handle my library's error directly. However, errors from MyLibrary can also be generated in any of the API handlers that the user writes (since they can interact with my library via the modified request object). These API handlers may be async.
Is there any solution to this issue?
Thank you

Centralized error handling for Resitify

I'm having trouble getting centralized error handling set up in my restify app. I'd like to trap certain Mongo errors, such as "E11000 duplicate key error" and then map them to a restify ConflictError.
If I just let the error bubble up from my Mongo call in a route, the client gets a 500 error.
I figured I should trap InternalServerError, but the below handler never gets called:
app.on('InternalServerError', function (req, res, err, cb) {
console.log('++++++++++++++++', err);
return cb(err);
});
I thought I could just use the express approach:
app.use(function (err, req, res, next){...
But restify handlers don't seem to take an error argument. I'm stumped after searching all the usual places. It seems my first approach should have just worked.
This might work for you. Set up a bunyan logger in your app.js file…
var bunyan = require('bunyan');
var log = new bunyan({
name: 'my_api',
streams: [
{
path: './error.log',
level: 'warn'
}
],
serializers: {req: restify.bunyan.serializers.req},
src: false
});
var server = restify.createServer({
log: log
});
Then in your controller do something like this….
var restify = require('restify');
try {
Model.findAll().then(function(vals){
res.send(vals);
next();
});
}
catch(e) {
req.log.error({req_id: req.id()}, 'Error attempting find.');
res.send(409, new restify.ConflictError("Problem executing search."));
next();
}

It is possible to enhance the express.js req and res variables without using a middleware function?

I'm working in a restful service using express.js and i want to enhance the req and res variables so for example you could write something like
app.use(function (req, res, next) {
res.Ok = function (data) {
res.status(200).send(data);
};
res.InternalError = function (err) {
res.status(500).send(err);
};
});
And later
router.get('/foo', function (req, res) {
res.Ok('foo');
})
This will send 'foo' in the body of the response and set the status code to 200 and is working perfectly.
My first question is if it is possible to add such functionality without a middleware function, lets say in a property or the prototype of the app variable?
The second question is if there are performance issues if you add many functionality with middleware functions at the app level. Are this functions attached to the request and response object per request or once on the application startup?
I know the Sails framework already do this but I'm wondering if they use middleware functions as well.
I keep digging and turns out that the request and response object are exposed in express using the __proto__ property.
var express = require('express'),
app = express();
app.response.__proto__.foo = function (data) {
this.status(200).send(data);
};
And later in the router
router.get('/foo', function (req, res, next) {
res.foo('test');
});
This will print test in your browser so it is possible to add functionality without using any middleware.
Note: I'm sure there are some drawbacks to this approach (overwriting express predefined properties, for example) but for testing purposes and adding very simple functionality I think is slightly better in terms of performance.
I'm not aware of any other way than using middleware. But in my opinion you could do the following to achieve nearly the same thing.
// Some Route
router.get('/foo', function(req, res, next) {
// ...
if(err) {
res.status(500);
return next(err);
}
return res.send('ok');
});
// Another route
router.get('/bar', function(req, res, next) {
// ...
if(badUserId) {
res.status(400);
return next('Invalid userId.');
}
req.result = 'hello';
return next();
});
router.use(function(req, res) {
// I prefer to send the result in the route but an
// approach like this could work
return res.send(req.result);
});
// Error Middleware
router.use(function(err, req, res, next) {
if(res.statusCode === 500) {
// Log the error here
return res.send('Internal server error');
} else {
return res.send(err);
}
});

Express : Call to next in error handler

I am implementing a node + express js app, and I am having issues calling to the next function into the error handler.
I have a render middleware which is called by next in each each controler, and I would like it to be the same with my error handler. What I do in controler is putting some viewProperties in the reqand then call the next middleware which retrieve these properties and render the response consequently.
function render(req, res, next) {
// viewName, title, args
var properties = req.viewProperties || {};
// We only handle a res.send(message)
if (properties.body) {
res.send(properties.body);
return;
}
// We only handle a res.redirect(url)
if (properties.redirect) {
res.redirect(properties.redirect);
return;
}
properties.lang = req.app.get('lang');
properties.title = properties.title || 'Message_Me';
properties.connected = req.session ? req.session.connected : false;
properties.firstname = req.session.userFirstname || 'anonymous';
res.render(properties.name, properties);
}
When I try using this middleware with my error handler, using next() the request is just pending on client side, and never recieved.
So I try to create the same middleware as an error handler : The same function but with an arity of 4 and then call next(err) in my error handler. This time the response is revieved client side but it is not rendered properly, it only shows up the stack trace.
The only way I found, it to copy this function in my error handler and paste it instead of calling to next. I don't understand why it can't work properly ?
my error handler :
function redirectError(err, req, res, next) {
// Ajax call running
if (req.xhr) {
req.viewProperties = { body : err.message };
return next(err);
}
req.viewProperties = { name : 'layout/error', title : 'Erreur', message : err.message, err : err };
// Here is the probleme
next()
// next(err);
}
EDIT
I tried another thing : I copied the render method into my error module as a simple function (not declared middleware). And then call to it instead of next in the redirectError error handler. that did the same behaviour. the function is called BUT nothing is recied on client side.
WHEREAS
If I copy the content of the render function INTO the redirectError everything works fine.
There really is something I don't understand here. It may be a deeper problem I have not yet noticed...
Riddles In The Dark
EDIT N2
I figured out my mistake !! I forgot a return statement in a if of another middleware. That made the nextbeing called twice, and a very bad bahaviour...
As a conclusion, a good practice to adopt, is to always use return when calling next !
And thank's to laggingreflex which made me carry on.
If there's an Error present (either thrown or passed through next) then only the next middleware which can handle the error (the one defined with arity of (err,req,res,next)) is called.
Conversely, if there isn't an Error present then the error handler middleware (err,req,res,next) is not called.
So in your case, your redirectError will only be called if there is an Error present, and your render only when there isn't.
To demonstrate:
app.use(function(req, res, next) {
throw(new Error('testing...'));
});
app.use(function(req, res, next) {
// This won't be called
});
app.use(function(err, req, res, next) {
// But This would
next(); // not passing any Error this time
});
app.use(function(err, req, res, next) {
// So now this won’t be called
});
app.use(function(req, res, next) {
// But this would
});

How to properly handle errors in Express?

I am beginning to work with Express JS and have run into an issue. I can't seem to figure out the proper way to handle errors.
For example, I have a web services API that serves an object called "event". I'd like to return a simple string of "cannot find event" when a user submits an event id that isn't found. Here is how I'm currently structuring my code:
app.get('/event/:id', function(req, res, next) {
if (req.params.id != 1) {
next(new Error('cannot find event ' + req.params.id));
}
req.send('event found!');
});
When I submit an id other than 1, Node crashes with the following output:
http.js:527
throw new Error("Can't set headers after they are sent.");
^
Error: Can't set headers after they are sent.
at ServerResponse.<anonymous> (http.js:527:11)
at ServerResponse.setHeader (/usr/local/kayak/node_modules/express/node_modules/connect/lib/patch.js:62:20)
at /usr/local/kayak/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js:72:19
at [object Object].<anonymous> (fs.js:107:5)
at [object Object].emit (events.js:61:17)
at afterRead (fs.js:878:12)
at wrapper (fs.js:245:17)
From what I can tell by using the node.js debugger, execution of the block of code continues after next() is called, meaning that req.send('event found!') tries to run. I don't want this to happen.
The only workaround that I've found is to simply throw a new Error() instead of "next-ing" it, but this results in a default Express HTML error page being generated. I'd like a little more control than that.
I have taken the time to read over the error handling section of the Express documentation, but I couldn't make sense of it.
You'll want to check out Express Error Handling. From there:
app.param('userId', function(req, res, next, id) {
User.get(id, function(err, user) {
if (err) return next(err);
if (!user) return next(new Error('failed to find user'));
req.user = user;
next();
});
});
The sweetspot that you are missing is the return next(...)
That's because you're doing it wrong: you already threw an Error (which will be processed by Express and return a 500 - Error page for the user or something like that) but you are also trying to send your own response to the client: res.send('event found!');
You should really check out the Express guide about Error Handling here: http://expressjs.com/guide/error-handling.html
What I would do in your example is:
function NotFound(msg){
this.name = 'NotFound';
Error.call(this, msg);
Error.captureStackTrace(this, arguments.callee);
}
app.get('/event/:id', function(req, res, next){
if (req.params.id != 1) {
throw new NotFound('Cannot find event ' + req.params.id);
} else {
res.send('event found!');
}
});
app.error(function(err, req, res, next){
if (err instanceof NotFound) {
res.render('404.ejs');
} else {
next(err);
}
});
You have a couple of problems in your code:
When responding to the client, you need to use the response object (res rather than req).
When sending an error to next, you should return, so the rest of the function doesn't run.
Here's your code after fixing those errors:
app.get('/event/:id', function(req, res, next) {
if (req.params.id != 1) {
return next(new Error('cannot find event ' + req.params.id));
}
res.send('event found!'); // use res.send (NOT req.send)
});

Categories