Handling 503 Error in Express/Node.js especially in TryCatch case - node.js

I have a special case for which I want to clear the possible reason for 503 Error. The following code snippet has a catch statement which runs when system is not able to find any results
app.post('/api/fetch/user', function(req, res){
var email = req.body.emailTxt;
db.one('SELECT * FROM users WHERE email=$1', [email])
.then(function(data){
console.log('DATA:', data);
var userCard = { id: data.user_id, name: data.user_name,
email: data.email, regDate: data.date_created };
res.status(200).json({ 'valid': true, '_payload': userCard });
})
.catch(function(error){
if(error.search(/No data returned from the query/im) > 0) // regex case insensitive search and search multiline as source string is multiline
res.status(500).send('Invalid Request Match');
else
res.status(500).send('ERROR: '+error);
})
});
When my API call is made to this API end point and when no result found the control moves in catch() which is fine but quite strangely it returns 503 - Request timeout error.
I have tried to to remove conditions in if() in order to debug but seems like no matter what but the if-else does not seem working in ExpressJs.
Note: Everything works well and also when control stays in .then(). If I remove if,else and keep simple error display/response return then everything works ok. There is nothing special included in my API; it is only one single page script I prepared to test API.

I think you got error in the .catch block.
Try to modify the code and see if this helps:
app.post('/api/fetch/user', function(req, res){
var email = req.body.emailTxt;
db.one('SELECT * FROM users WHERE email=$1', [email])
.then(function(data){
console.log('DATA:', data);
var userCard = { id: data.user_id, name: data.user_name,
email: data.email, regDate: data.date_created };
res.status(200).json({ 'valid': true, '_payload': userCard });
})
.catch(function(error){
console.error(error); //never ignore errors!
try {
//i think error is an Error Object here, so it doesn't have .search function
if(error.search(/No data returned from the query/im) > 0) // regex case insensitive search and search multiline as source string is multiline
res.status(500).send('Invalid Request Match');
else
res.status(500).send('ERROR: '+error);
} catch (err) {
console.error(err);
res.status(500).send('some unknown error');
};
});
});
Edit: Sorry, removed .finally because you may send response twice.
Edit, better approach to handle error in .catch block.
//make catch block error safe to make sure no error occurs
if (error && error.message == 'No data returned from the query.') {
res.status(500).send('Invalid Request Match');
} else {
res.status(500).send('ERROR: '+error);
}

We use response codes in ExpressJs quite intensively when creating an API service. So it seems a right way that we make use of them directly instead of doing if-else in catch().
Hence, the right way would be:
.catch(function(error){
console.log('ERROR:', error);
res.status(204).send('No Content; Invalid Request Match');
})
However, If you want to display/return detailed message you can do that as well. You can check: http://expressjs.com/en/api.html#res for details on ways you can response back. You can render an HTML template, or return JSON response or even multiline text.
I don't know why if-else creates problem but you can go other way around.
In your specific case the error does not have .search() method attached to it. So better to parse it to string first using .toString();.

Related

Catch 404 on xhr.js, when Axios GET is called and express server sends .json()

On my client Vue.js application the console gives me an 404 error, when calling my express API, with an invalid API token.
E.g. calling http://localhost:8081/confirmation/invalidToken
gives, me
xhr.js?b50d:172 GET http://localhost:8081/confirmation/a 404 (Not Found)
Of course it is possible for someone to use that invalid link, so I want to handle these errors instead of printing the error on the console.
If on my express server side, I send the response, like this:
return res.status(404);
Then the console error disappears.
Edit: However this only seems to be the case, because the request is not finished and it's waiting. After a while, the console logs a "net::ERR_CONNECTION_RESET" error.
It's only appearing if I send the response like this:
return res.status(404).send({
message: 'No valid link!',
error,
});
or this:
return res.status(404).send({
message: 'No valid link!',
error,
});
Catching on client side is not working for this problem.
public async sendConfirmation(token: string): Promise<any> {
try {
return axios.get(this.baseURL + '/confirmation/' + token);
} catch (error) {
// tslint:disable-next-line:no-console
console.log(error.response);
}
}
sendConfirmation(this.token)
.then((res) => {
// tslint:disable-next-line:no-console
console.log(res);
if (res.status === 404) {
throw new Error("404");
}
this.data = res.data;
if (res.status === 201) {
this. messagetype = 1;
} else if (res.status === 200) {
this.messagetype = 2;
}
})
.catch((err) => {
this.messagetype = 0;
// tslint:disable-next-line:no-console
// console.log(err );
});
Anyone knows a way to catch that console error, not having to remove the custom message in the server result?
I had same error in heroku in a webpack project with variables environments, i had path of .env file set to local path like c:/project/.env, so the variable of server always return undefined, changing path to relative one fixed the bug:
if (process.env.REACT_APP_ENV === "development") {
require("dotenv").config({
path: ".env.development",
});
}
also check the .env file make sure there is no quotes:
SERVER_URI=https://yourApp.com
and not this:
SERVER_URI="https://yourApp.com"
you have to stringify it later in webpackconfig.
this may help someone or give him a hint.
Well, it's a browser behaviour, that shows the error.
Certain response codes, will in some browsers throw those console messages.
There seems no way to prevent this in a project.

Capture a JSON GET response in a variable?

I'm using request-promise to get data from an endpoint that I have.
Is it posible to 'capture' a json response in a variable to use it anywhere?
try{
var gamer = '';//variable to capture json data
var options = {
uri: 'http://localhost:4000/gamers/'+gamer._id+'/find',
json: true
};
RequestPromise(options)
.then(function (data) {
gamer = data;//capturing response
})
.catch(function (err) {
console.log("Error saving player data !");
});
.... do something with gamer ....
}catch(err){
res.status(500).send({
message: err.message || 'An error occurred generating player teams !'
});
}
The reason that I need to do this is because actually I don't have access to the database to get that information, so my only option is to consume an API to get information through collections id's.
Your doing a lot of things correctly already. The issue is your gamer variable will get assigned the value you expect first when your promise resolves. There are many ways to skin this cat, but to get you started try performing whatever you want to perform on the gamer variable in .then(), like this:
try{
var gamer = '';//variable to capture json data
var options = {
uri: 'http://localhost:4000/gamers/'+gamer._id+'/find',
json: true
};
RequestPromise(options)
.then(function (data) {
gamer = data;//capturing response
// here is the rigth place perofrm operations on the answer, as this part of the code gets executed after promise reolves. BTW. Then you don't need variable gamer.
})
.catch(function (err) {
console.log("Error saving player data !");
});
// here is not the right place to do something with gamer as this is executed as soon as promise is initialized, not as it resolves. This means your variable will have initial value here
}catch(err){
res.status(500).send({
message: err.message || 'An error occurred generating player teams !'
});
}

express how to handle errors with redirects & messages

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;

Proper way to set response status and JSON content in a REST API made with nodejs and express

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).

Nodejs inserting data to mongodb. It takes too much time

Hi i am developing nodejs application. I am inserting data to mongodb but my page always in 'loading' mode. But strange thing is my data inserted to mongodb immediately but page load not stopping. My code is shown below:
app.post('/Management/Post/New',function(req, res){
new Post({
title:req.body.post.title,
body:req.body.post.body,
keywords:req.body.post.keywords
}).save(function (err, docs){
if(err) {
return res.render(__dirname + "/views/createpost", {
title: 'Yeni Gönderi Oluştur',
stylesheet: 'postcreate',
error: 'Gönderi oluşturulurken bir hata ile karşılaşıldı'
});
}
console.log('Gönderi oluşturuldu');
});
});
Have no idea.
You only send a response when there is an error. If there's no error, you server never sends anything back: that's why the page seems to always be loading.
You need to send a response when you have no error, like this:
.save(function (err, docs){
if(err) { // Executed when there was an error with Mongo
return res.render(...);
} else { // Executed when everything is fine
return res.render(...);
}
});
You aren't handling the success scenario except for a console.log. You need a res.render() or res.redirect() on success, not just error

Resources