My node.js app is modeled like the express/examples/mvc app.
In a controller action I want to spit out a HTTP 400 status with a custom http message.
By default the http status message is "Bad Request":
HTTP/1.1 400 Bad Request
But I want to send
HTTP/1.1 400 Current password does not match
I tried various ways but none of them set the http status message to my custom message.
My current solution controller function looks like that:
exports.check = function( req, res) {
if( req.param( 'val')!=='testme') {
res.writeHead( 400, 'Current password does not match', {'content-type' : 'text/plain'});
res.end( 'Current value does not match');
return;
}
// ...
}
Everything works fine but ... it seems not the the right way to do it.
Is there any better way to set the http status message using express ?
None of the existing answers accomplish what the OP originally asked for, which is to override the default Reason-Phrase (the text appearing immediately after the status code) sent by Express.
What you want is res.statusMessage. This is not part of Express, it's a property of the underlying http.Response object in Node.js 0.11+.
You can use it like this (tested in Express 4.x):
function(req, res) {
res.statusMessage = "Current password does not match";
res.status(400).end();
}
Then use curl to verify that it works:
$ curl -i -s http://localhost:3100/
HTTP/1.1 400 Current password does not match
X-Powered-By: Express
Date: Fri, 08 Apr 2016 19:04:35 GMT
Connection: keep-alive
Content-Length: 0
You can check this res.send(400, 'Current password does not match')
Look express 3.x docs for details
UPDATE for Expressjs 4.x
Use this way (look express 4.x docs):
res.status(400).send('Current password does not match');
// or
res.status(400);
res.send('Current password does not match');
You can use it like this
return res.status(400).json({'error':'User already exists.'});
One elegant way to handle custom errors like this in express is:
function errorHandler(err, req, res, next) {
var code = err.code;
var message = err.message;
res.writeHead(code, message, {'content-type' : 'text/plain'});
res.end(message);
}
(you can also use express' built-in express.errorHandler for this)
Then in your middleware, before your routes:
app.use(errorHandler);
Then where you want to create the error 'Current password does not match':
function checkPassword(req, res, next) {
// check password, fails:
var err = new Error('Current password does not match');
err.code = 400;
// forward control on to the next registered error handler:
return next(err);
}
At server side(Express middleware):
if(err) return res.status(500).end('User already exists.');
Handle at Client side
Angular:-
$http().....
.error(function(data, status) {
console.error('Repos error', status, data);//"Repos error" 500 "User already exists."
});
jQuery:-
$.ajax({
type: "post",
url: url,
success: function (data, text) {
},
error: function (request, status, error) {
alert(request.responseText);
}
});
When using Axios you can retrieve the custom response message with:
Axios.get(“your_url”)
.then(data => {
... do something
}.catch( err => {
console.log(err.response.data) // you want this
})
...after setting it in Express as:
res.status(400).send(“your custom message”)
My use-case is sending a custom JSON error message, since I'm using express to power my REST API. I think this is a fairly common scenario, so will focus on that in my answer.
Short Version:
Express Error Handling
Define error-handling middleware like other middleware, except with
four arguments instead of three, specifically with the signature (err,
req, res, next). ... You define error-handling middleware last, after
other app.use() and routes calls
app.use(function(err, req, res, next) {
if (err instanceof JSONError) {
res.status(err.status).json({
status: err.status,
message: err.message
});
} else {
next(err);
}
});
Raise errors from any point in the code by doing:
var JSONError = require('./JSONError');
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);
Long Version
The canonical way of throwing errors is:
var err = new Error("Uh oh! Can't find something");
err.status = 404;
next(err)
By default, Express handles this by neatly packaging it as a HTTP Response with code 404, and body consisting of the message string appended with a stack trace.
This doesn't work for me when I'm using Express as a REST server, for example. I'll want the error to be sent back as JSON, not as HTML. I'll also definitely not want my stack trace moving out to my client.
I can send JSON as a response using req.json(), eg. something like req.json({ status: 404, message: 'Uh oh! Can't find something'}). Optionally, I can set the status code using req.status(). Combining the two:
req.status(404).json({ status: 404, message: 'Uh oh! Can't find something'});
This works like a charm. That said, I find it quite unwieldy to type every time I have an error, and the code is no longer self-documenting like our next(err) was. It looks far too similar to how a normal (i.e, valid) response JSON is sent. Further, any errors thrown by the canonical approach still result in HTML output.
This is where Express' error handling middleware comes in. As part of my routes, I define:
app.use(function(err, req, res, next) {
console.log('Someone tried to throw an error response');
});
I also subclass Error into a custom JSONError class:
JSONError = function (status, message) {
Error.prototype.constructor.call(this, status + ': ' + message);
this.status = status;
this.message = message;
};
JSONError.prototype = Object.create(Error);
JSONError.prototype.constructor = JSONError;
Now, when I want to throw an Error in the code, I do:
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);
Going back to the custom error handling middleware, I modify it to:
app.use(function(err, req, res, next) {
if (err instanceof JSONError) {
res.status(err.status).json({
status: err.status,
message: err.message
});
} else {
next(err);
}
}
Subclassing Error into JSONError is important, as I suspect Express does an instanceof Error check on the first parameter passed to a next() to determine if a normal handler or an error handler must be invoked. I can remove the instanceof JSONError check and make minor modifications to ensure unexpected errors (such as a crash) also return a JSON response.
If your goal is just to reduce it to a single/simple line, you could rely on defaults a bit...
return res.end(res.writeHead(400, 'Current password does not match'));
Well in the case of Restify we should use sendRaw() method
Syntax is:
res.sendRaw(200, 'Operation was Successful', <some Header Data> or null)
Related
I am new to node.js, I have a requirement where i am trying to handle the error that is being returned from the callback method/function. How do i assign the error that is being sent as part of callback to my response payload.
The node module that i am calling to validate swagger supports both callback function as well as Promise.
So how do i assign the err to my response payload. Currently i am just logging to my console, but since we plan to expose this through an API i would like to return the error information in the response payload.
var express = require('express');
var SwaggerParser = require('swagger-parser');
var myParser = require("body-parser");
var app = express();
var fs = require("fs");
app.use(myParser.urlencoded({extended : true}));
app.use(myParser.json());
function errorHandler (err, req, res, next) {
res.status(500)
res.render('error', { error: err })
}
app.post('/v1/swagger/validate',function(request,response){
/**SwaggerParser.validate(request.body, function(err, api) {
if (err) {
console.error(err);
console.log("Inside Error");
}
else {
console.log("API name: %s, Version: %s", api.info.title, api.info.version);
console.log("Inside Success");
}
}); **/
SwaggerParser.validate(request.body)
.then(function(api) {
console.log("API name: %s, Version: %s", api.info.title, api.info.version);
})
.catch(function(err) {
console.error(err);
});
response.end();
});
app.listen(8082);
You can decide how you want to communicate the error back from your API.
If the error is internal to your server and not something caused directly by a poor API request, then you probably return a 500 status code (internal server error).
response.status(500).end();
If there's something meaningful to communicate back to the other end of the API (like nothing found for the query or a specific validation error), then you have to design what you want that to be. For example, you could be sending back some JSON:
response.json({result: null, msg: "Validation Failed"});
So, it's really up to you what you want your API to return for a given situation. The main point is that you decide what you want that response to be and you send it as the response, even in error conditions. You need to make it a design that makes sense to the consumers of your API so they can clearly tell when they have a proper result and clearly tell when they have an error and if the error is their fault they need to be able to tell why it is their fault based on the response (so they more detail you provide on the issue in the response, the better).
I can't seem to wrap my head around how to properly handle errors.
The basic 404, is no problem (simply set header 404 and render 'not found' page). But let's say for example:
You find a user by id, but the user doesn't exist. I suppose for this you set the header-status to 500. But how do you redirect the page back (or simply assign a redirect page) and set a flashmessage?
In most tutorials I usually find the following:
model.SignUp.forge({id: req.params.id}).fetch({withRelated: ['usermeta']}).then(function(user) {
res.render('admin/pages/users/details', {title: 'Signups', error: false, details: user});
}).catch(function(err) {
res.status(500).json({error: true, data: {message: err.message}});
});
You simply catch the problem whenever an error occurs. I also come across this sometimes:
transporter.sendMail(mailOptions, function(err) {
if(err) {
req.flash('error', 'blablabla');
res.redirect('back');
}
});
In the first case you return a json file but no redirect or render. In the second part no status has been provided.
What practices do you guys implement?
I'm a huge fan of central error handling in my express apps. How does this work? Well, I have a library of HTTP error objects that all have a 'status' property on them. All my route handlers and middeware return a callback with one of those error objects depending on what happened, and do not call res.send (or any other res.* method) if there was an error. I then have an error handling middleware (or more than one, if I it's getting to be complex) that decides if I want to do a redirect or just send the response code, or whatever depending on the needs of the app.
Taking your example:
app.post('/signup', function(req, res, next){
model.SignUp.forge({id: req.params.id}).fetch({withRelated: ['usermeta']}).then(function(user) {
res.render('admin/pages/users/details', {title: 'Signups', error: false, details: user});
}).catch(function(err) {
return next(new HttpServerError(err));
});
}
an HttpServerError has a status of 500, and so I have at least a 'catch all' error handling middleware that looks like this (in the case of a json api):
app.use(function(err, req, res, next){
console.log(err.stack);
res.status(err.status).send({message: err.clientMessage});
});
You can also do multiple handlers, and render or redirect based on the state of the request (e.g. accepts headers or type of error).
For example, in a traditional web app, I might use the name of the error to figure out what template to render, and I might redirect to a login page if it's a 403 error.
For sake of completeness, here's an example HttpServerError:
'use strict';
const util = require('util');
function HttpServerError(message){
this.message = message;
this.clientMessage = 'Dangit! Something went wrong on the server!';
this.status = 500;
Error.captureStackTrace(this, NotFoundError);
}
util.inherits(HttpServerError, Error);
HttpServerError.prototype.name = 'HttpServerError';
module.exports = HttpServerError;
I'm curious if there's a good way to handle this with express 4.0.
There are times where there is a problem with either Stripe, or my connection to Stripe that needs to be addressed. However, I obviously do not want users to know about this. I want to display a message 'There was a problem completing your order, please contact support.' while safely logging the message with some information for me to handle it.
I suspect I can do this in middleware. However, I'm not sure how. I would like to catch these errors as they are happening and dump them to a logfile of some kind (suggestions would be great) so I can handle it.
Is there a standard way of doing this? How would I accomplish this?
Thank you!
You're thinking about this the wrong way. Instead of exposing 3rd party errors, explicitly define each possible failure case in your route.
// bad
app.use(function (err, req, res, next) {
res.status(err.status).json({ error: err.message })
})
Instead mark errors to be exposed:
app.use(function (err, req, res, next) {
if (err.expose) {
res.status(err.status).json({ code: err.code, error: err.message })
} else {
reportError(err, req)
res.status(500).json({ code: "unknown", error: "unknown error" })
}
})
You need to re-throw actual api errors.
function createError(status, message) {
var err = new Error(message)
err.expose = true
err.status = status
return err
}
function changeCard(user, data) {
return postStripeCards(user, data)
.catch({ type: "card_error" }, function (err) {
throw createError(400, "invalid card")
})
}
Uncaught errors are programmer mistakes which should be reported and fixed. Anything that makes it through is a bug.
function reportError (err, req) {
// log error
console.error(err.stack)
// send to rollbar
rollbar.handleError(err, req)
// maybe send an email
mailgun.send({
from: "bot#myapp.com",
to: "me#gmail.com",
subject: "My App: " + err.message,
text: err.stack + "\n\n" + JSON.stringify(req),
})
// pager duty, airbrake, etc
}
It takes work, but it means your API is well-defined.
When I use domain.dispose() in Node.js expressjs based HTTP Server, the client making HTTP sees a response code of 0 (Could not get any response). If I remove domain.dispose() I receive 500 error with the desired error message. Below is my code
//Enable domains
app.use(function(req, res, next){
var createDomain = require('domain').create;
var domain = createDomain();
domain.add(req);
domain.add(res);
domain.run(function() {
next();
});
domain.on('error', function(e) {
//no further domain watch required
domain.dispose(); //if I remove this line status code of 500 is received on client, otherwise 0 or no response is received
next(e);
});
});
//Respond with 500 for Unhandled errors
app.use(function(err, req, res, next) {
// If the error object doesn't exists
if (!err) return next();
// Log it
req.log.error(err);
//console.error(err.stack);
try{
if(req.path && req.path.indexOf('/api/') === 0){
if(!res.headersSent){
console.log('responded with an error');
res.status(500).send({error: err.message});
console.log('responded with an error ACK');
}
return;
}
// Error page
res.status(500).render('500', {
error: err.stack
});
} catch(ex){
console.log('An error occured while responding 500');
req.log.error(ex);
}
});
Can anyone explain this or a better solution? Removing domain.dispose() may cause further exceptions, which may cause to re-enter the domain, and I do want to acknowledge client with the exception message as in my code.
This is expected behaviour of domains. Since you have explicitly added req and res to domain, so they are disposed as well. Don't use dispose, it does unexpected things. When you catch an error with domain the only sensible thing to do is to shutdown the process as quickly as possible.
I am playing around with Nodejs and express by building a small rest API. My question is, what is the good practice/best way to set the code status, as well as the response data?
Let me explain with a little bit of code (I will not put the node and express code necessary to start the server, just the router methods that are concerned):
router.get('/users/:id', function(req, res, next) {
var user = users.getUserById(req.params.id);
res.json(user);
});
exports.getUserById = function(id) {
for (var i = 0; i < users.length; i++) {
if (users[i].id == id) return users[i];
}
};
The code below works perfectly, and when sending a request with Postman, I get the following result:
As you can see, the status shows 200, which is OK. But is this the best way to do this? Is there a case where I should have to set the status myself, as well as the returned JSON? Or is that always handled by express?
For example, I just made a quick test and slightly modified the get method above:
router.get('/users/:id', function(req, res, next) {
var user = users.getUserById(req.params.id);
if (user == null || user == 'undefined') {
res.status(404);
}
res.json(user);
});
As you can see, if the user is not found in the array, I will just set a status of 404.
Resources/advices to learn more about this topic are more than welcome.
Express API reference covers this case.
See status and send.
In short, you just have to call the status method before calling json or send:
res.status(500).send({ error: "boo:(" });
You could do it this way:
res.status(400).json(json_response);
This will set the HTTP status code to 400, it works even in express 4.
status of 200 will be the default when using res.send, res.json, etc.
You can set the status like res.status(500).json({ error: 'something is wrong' });
Often I'll do something like...
router.get('/something', function(req, res, next) {
// Some stuff here
if(err) {
res.status(500);
return next(err);
}
// More stuff here
});
Then have my error middleware send the response, and do anything else I need to do when there is an error.
Additionally: res.sendStatus(status) has been added as of version 4.9.0
http://expressjs.com/4x/api.html#res.sendStatus
A list of HTTP Status Codes
The good-practice regarding status response is to, predictably, send the proper HTTP status code depending on the error (4xx for client errors, 5xx for server errors), regarding the actual JSON response there's no "bible" but a good idea could be to send (again) the status and data as 2 different properties of the root object in a successful response (this way you are giving the client the chance to capture the status from the HTTP headers and the payload itself) and a 3rd property explaining the error in a human-understandable way in the case of an error.
Stripe's API behaves similarly in the real world.
i.e.
OK
200, {status: 200, data: [...]}
Error
400, {status: 400, data: null, message: "You must send foo and bar to baz..."}
I am using this in my Express.js application:
app.get('/', function (req, res) {
res.status(200).json({
message: 'Welcome to the project-name api'
});
});
The standard way to get full HttpResponse that includes following properties
body //contains your data
headers
ok
status
statusText
type
url
On backend, do this
router.post('/signup', (req, res, next) => {
// res object have its own statusMessage property so utilize this
res.statusText = 'Your have signed-up succesfully'
return res.status(200).send('You are doing a great job')
})
On Frontend e.g. in Angular, just do:
let url = `http://example.com/signup`
this.http.post(url, { profile: data }, {
observe: 'response' // remember to add this, you'll get pure HttpResponse
}).subscribe(response => {
console.log(response)
})
res.status(500).jsonp(dataRes);
try {
var data = {foo: "bar"};
res.json(JSON.stringify(data));
}
catch (e) {
res.status(500).json(JSON.stringify(e));
}
The best way of sending an error response would be return res.status(400).send({ message: 'An error has occurred' }).
Then, in your frontend you can catch it using something like this:
url: your_url,
method: 'POST',
headers: headers,
data: JSON.stringify(body),
})
.then((res) => {
console.log('success', res);
})
.catch((err) => {
err.response && err.response.data && this.setState({ apiResponse: err.response.data })
})
Just logging err won't work, as your sent message object resides in err.response.data.
Hope that helps!
You could do this
return res.status(201).json({
statusCode: req.statusCode,
method: req.method,
message: 'Question has been added'
});
FOR IIS
If you are using iisnode to run nodejs through IIS, keep in mind that IIS by default replaces any error message you send.
This means that if you send res.status(401).json({message: "Incorrect authorization token"}) You would get back You do not have permission to view this directory or page.
This behavior can be turned off by using adding the following code to your web.config file under <system.webServer> (source):
<httpErrors existingResponse="PassThrough" />
res.sendStatus(status) has been added as of version 4.9.0
you can use one of these res.sendStatus() || res.status() methods
below is difference in between res.sendStatus() || res.status()
res.sendStatus(200) // equivalent to res.status(200).send('OK')
res.sendStatus(403) // equivalent to res.status(403).send('Forbidden')
res.sendStatus(404) // equivalent to res.status(404).send('Not Found')
res.sendStatus(500) // equivalent to res.status(500).send('Internal Server Error')
I hope someone finds this helpful
thanks
I don't see anyone mentioned the fact that the order of method calls on res object is important.
I'm new to nodejs and didn't realize at first that res.json() does more than just setting the body of the response. It actually tries to infer the response status as well. So, if done like so:
res.json({"message": "Bad parameters"})
res.status(400)
The second line would be of no use, because based on the correctly built json express/nodejs will already infer the success status(200).