Express single response workaround - javascript

I am stuck in a bit of a dilemma here where once my user logs in I want to redirect them to the dashbord page but also send their json details to my client side javascript. I know that there can only be one res. send /end/json in a response and that I can send dynamic data using view engines.The reason why I want to send data separately is because I do not merely want to render it but rather use the data in my client side JS so that I can use it later for sockets in a chat application. I have tried a lot of things from using continuous local variables to try and create a middleware or an automatic redirect. The problem is no matter what the res.json() is hard to embed in a middleware as the very moment it is called there is no scope for declaring a next or redirect. Here is what my code looks like for the login route:
router.get(’/’, (req,res)=>{
console.log(req.user._id);
User.findOne({
"_id": req.user._id
}, function(err, foundUser) {
if (err) {
console.log(err);
return res.status(500).json({
ok: false,
error: err
});
} else {
console.log(foundUser); //THE ELEMENT IS FOUND
return res.status(200).json({
ok: true,
data: foundUser
});
}
});
res.sendFile('chat.html', { root: path.join(__dirname, '../views/') });
});

you can make ajax request from your page to fetch the data you want and save it in your client side.

You need to make your chat.html page request the json data. This means you need two routes:
router.get(’/’, (req,res)=>{
es.sendFile('chat.html', { root: path.join(__dirname, '../views/') });
});
router.get(’/myself’, (req,res)=>{ // I normally call this route "myself"
// but you can call it anything you want
console.log(req.user._id);
User.findOne({
"_id": req.user._id
}, function(err, foundUser) {
if (err) {
console.log(err);
return res.status(500).json({
ok: false,
error: err
});
} else {
console.log(foundUser); //THE ELEMENT IS FOUND
return res.status(200).json({
ok: true,
data: foundUser
});
}
});
});
Now you need your chat.html file to make a request for the new /myself data. There are various ways to do this but for modern browsers you can use fetch:
chat.html
<html>
<head>
... rest of your html head
<script>
fetch('/myself')
.then(res => res.json())
.then(res => {
if (res.ok === false) {
// Handle your error here, I'm just alerting it:
alert(res.error);
}
else {
let user = res.data;
// Now you can do anything with the user data
// in here. I'm just logging it:
console.log('user =', user);
}
});
</script>
</head>
<body>
... rest of your html code
</body>
</html>

Related

Internal Server Error on failed in router

In my router, before I goes to the page I launch an rest api request to get data from server in by beforeEnter clause like below:
beforeEnter: (to, form, next) => {
getData().then(
(response) => {
//some logic to get data
next(); //if no error redirect to page
},
(error) => {
next(false); //on error not redirect on page - on this moment i want to show info about internal server error
});
}
and right now i have an question, how to show an toast/notification with "Internal server error" info when I have an error in my beforeEnter?
thanks for any help
Hmmm, Ok, I do it
on error:
(error) => {
HelpersService.internalServerErrorToast();
next(false);
}
in service:
internalServerErrorToast() {
let bootStrapToaster = new BToast();
bootStrapToaster.$bvToast.toast("500", {
title: "Internal Server Error",
toaster: "b-toaster-bottom-right",
solid: true,
variant: "danger",
appendToast: false,
noCloseButton: true,
toastClass: "internalErrorToast",
});
}
Why you are not using catch. If you are using then, you can use catch.
beforeEnter: function(to, form, next) {
this.getData().then((response) => {
next();
}).catch(error => {
throw error
})
}
Try this. If not work, comment, We will do something else.

How to sort NeDB database in get response? (Javascript callback/arrow function syntax confusion)

I have an express server and a simple NeDB database. I can successfully get the whole database like so:
app.get('/api', (request, response) => {
//queuery the database for everything
db
.find({}, (error, data) => {
if (error) {
response.end();
console.log(error)
return;
}
console.log(data)
response.json(data)
})
But I noticed the results are, for some reason, not the same order as the database file. I want to sort by one of the timestamps. The database looks like:
...
{"lat":1,"lon":7,"timestamp":1585781054239,"_id":"3cZvJfQyLEXK0SZo","createdAt":{"$$date":1585781054240},"updatedAt":{"$$date":1585781054240}}
{"lat":1,"lon":2,"timestamp":1585781047536,"_id":"DN9bpd1FygEowgtc","createdAt":{"$$date":1585781047538},"updatedAt":{"$$date":1585781047538}}
{"lat":1,"lon":6,"timestamp":1585781052398,"_id":"Dzp6x0xo3QM960Rm","createdAt":{"$$date":1585781052400},"updatedAt":{"$$date":1585781052400}}
{"lat":1,"lon":5,"timestamp":1585781051174,"_id":"KswtMYzV2QBE3xkb","createdAt":{"$$date":1585781051176},"updatedAt":{"$$date":1585781051176}}
...
I admittedly haven't quite wrapped my head around how the callbacks work in this code. I have tried something like the following but it returns a 500 GET error to the client and returns "TypeError: Cannot read property 'sort' of undefined" to the server:
app.get('/api', (request, response) => {
//queuery the database for everything
db
.find({}, (error, data) => {
if (error) {
response.end();
console.log(error)
return;
}
// console.log(data)
// response.json(data)
})
.sort({ createdAt: -1 }, (data) => {
console.log(data)
response.json(data)
});
});
I wonder if it should be nested in the .find() function but at this point I'm quite in over my head and I believe I'm just not understanding the syntax. I have found examples of sorting but not in this context.
You can write something like this to sort it via timestamp:
database.find({}).sort({"timestamp":-1}).exec(function(err, data) {
if (err) {
response.end();
return;
}
console.log(data);
});

user.save won't run the callback function

I'm trying to save information to my user schema in my database. I'm doing this using "user.save" but for some reason the code within the parenthesis is not run.
user.save(function(err) {
//THIS CODE DOESNT SEEM TO RUN
if (err) {
console.log(err);
} else {
res.json({ message: 'given a reset-token' })
}
//
});
So I switched to the following code since I needed to get a success message from the server:
user.save((err) => {
console.log('hello');
if (err) {
console.log(err);
console.log('err2');
res.status(404).json({ message: 'Save error' });
}
}).then(() => {
res.status(201).json({ message: 'Activated' });
});
Witch successfully sends me the status code when changes to the user have been pushed to the database. Could anyone explain why the second one works and the first one doesn't? And if there is a better way to write this code?

Angular 4 & Passport API authentication

I'm building a web app with the MEAN Stack. What I am trying to achieve is that when the user logs in his user information get fetched by Angular from my REST API. I set up the API route http://localhost:3000/api/user/profile which should respond with json including the user object.
router.get('/user/profile', function(req, res, next){
//console.log(req);
if(req.user === undefined){
res.json({
success: false,
msg: 'Unautorized'
});
} else {
res.json({
success: true,
user: {
id: req.user.steam.id,
name: req.user.steam.name,
avatar: req.user.steam.avatar,
avatarmedium: req.user.steam.avatarmedium,
avatarfull: req.user.steam.avatarfull
}
});
}
});
When the user logs in Angular start a GET-Request:
ngOnInit() {
this.authService.getProfile().subscribe(profile => {
this.user = profile.user;
console.log(profile);
},
err => {
console.log(err);
return false;
});
}
getProfile():
getProfile(){
return this.http.get('http://localhost:3000/api/user/profile')
.map(res => res.json());
}
When I load up my site, log in, and go to the profile page the returned object contains success: false and the message 'Unauthorized' instead of the user object. Why is this happening?
I completely redesigned my approach. I implemented json web token which now sends a token (containing all user data) to the user through a url parameter once he signs in.

How to handle error in Angular Controller from MongoDB database update/delete in Express?

I am trying to figure out how to handle an error when deleting or updating a document in MongoDB in Angular JS?
I have the following route in Node/Express:
function handleError(res, reason, message, code) {
console.log("ERROR: " + reason);
//log the reason for the error
res.status(code || 500).json({
"error": message
});
}
app.delete("/polls/:id", auth, function(req, res) {
db.collection(POLLS_COLLECTION).deleteOne({
_id: new ObjectID(req.params.id), userID: req.user.id
//userID must match the req.user.id from Passport to make sure the poll belongs to the user
}, function(err, doc) {
if (err) {
handleError(res, err.message, "Failed to delete poll");
} else {
res.status(204).end();
}
});
});
The following in an Angular JS controller:
$scope.deleteThisPoll = function(){
Polls.deletePoll($routeParams.pollId)
.then(function(response){
alert("Poll deleted!");
var url = "/mypolls/" + $scope.userID;
$location.path(url);
}, function(response){
alert("Error deleting poll");
console.log(response);
})
};
deleteThisPoll in the controller calls a deletePoll service that sends a a request to the route:
this.deletePoll = function(pollId){
var url = "/polls/" + pollId;
return $http.delete(url);
};
What I want is to alert "Error deleting poll" from the Angular controller when the database delete is not executed (because for example user is not authenticated or the poll doesnt belong to the user) and "Poll Deleted" when the delete was successfull.
However: the error callback is never used and the app always alerts "Poll deleted!" no matter if the document was deleted or not deleted.
Doesn't my route send an error response when the delete was not executed and will it not hit my Angular error callback?
You can do like code below
Put this HTML code where you want to show error message :
<div style="color:red;">
{{error}}
</div>
In your angular js controller :
$scope.deleteThisPoll = function(){
Polls.deletePoll($routeParams.pollId)
.then(function(response){
alert("Poll deleted!");
var url = "/mypolls/" + $scope.userID;
$location.path(url);
}, function(response){
$scope.error="Any error message you like to show";
console.log(response);
})
};
If your API return an error. you can catch it like this :
Polls.deletePoll($routeParams.pollId).then(function(response) {
//SUCCESS CODE
}).catch(function(error) {
//NOTIFY ERROR
//NotifyService.display(error);
console.log(error);
});
thanks guys. I found out that MongoDB for some reason always returns a result object even when there was no delete/update. I solved this by checking for the result.deletedCount propety that is set to 1 or 0. Like so:
if(err){
res.status(500).end();
}
if(result.deletedCount === 0){
res.status(404).end();
//error handling in Angular error callback
} else {
res.status(204).end();
//error handling in Angular success callback
}
});
});
this makes sure that not always a 204 is send whether or not the delete was successfull.

Categories

Resources