Is there any way how to communicate between those two?
Lets say i have a server.
Someone uploads a file , the server process the file and find that its incorrect and send event to the client. The client catch the event and does some DOM manipulation displaying fancy styled error message.
Is something like that possible?
Yes - of course this is possible. Since you have tagged your question with javascript and nodeJS, I'll show you one example with javascript for the server, i.e. nodeJS.
It uses callback functions for routes. This allows you to do just what you describe, build logic into any given request. Below is a standard route request from a user to login, you can see below that there is a simple 'if' statement which will execute code if 'something went wrong' and return a message to the user. Take a look:
app.post('/login', function(req, res, next){
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.send({error : 'something went wrong :('}); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.send({success:'success'});
});
})(req, res, next);
})
Related
I am getting data from an API and am displaying it on my local server.
Below is my code to get data which matches the ID from the API data:
router.get('/:id', async (req, res) => {
checkString(req.params.id)
try {
const person = await peopleData.getPersonById(req.params.id);
res.json(person);
} catch (e) {
res.status(404).json({ message: 'There is no person with that ID' });
}
If there is no match I want to display the message like in the catch block, but the code does not go there as not getting a match is not an error technically.
So I tried the below code to get this message:
router.get('/:id', async (req, res) => {
checkString(req.params.id)
try {
const person = await peopleData.getPersonById(req.params.id);
if(!person) res.json('There is no person with that ID'); // Added new line here
res.json(person);
} catch (e) {
res.status(404).json({ message: 'There is no person with that ID' });
}
This does the work but it prints the message with quotes around as a string, is there a way I can display the message in the catch block if no match is found?
You can throw an error and the catch will display it.
if(!person) throw new Error("There is no person with that ID");
....
then in the catch...
catch(e){
res.status(404).json({ message: e.message })
}
If you're sending people to a fullscreen "error stack" page, then you may not need to use res.json()! You can also use res.send()
if(!person){ res.send('<p>There is no person with that ID</p>'; return; }
// Or
if(!person){ res.send('There is no person with that ID'; return; }
You are returning Json responses, so it looks like your consumer is not a web page but another app. If so, you should return undefined or null if there is no person found, and let the web page or consumer decide what message to show. Reasons are:
It should be easier to modify web pages than code, and typically the UI or marketing people will always want to fine tune (usually many times) every message on a web page.
Your app is an API app. The place where the user not found message is to be shown can be many steps away. Or it may be inappropriate to show the message at all, for example the consuming app might want to redirect to/show a registration page instead if user is not found.
Your web site may be multi-lingual, and you don't want the back-end to be involved in this.
"User not found" in many situations is not really an error, but it all depends on your application.
The catch block in your case should be used to handle other errors, for example, your database server might be down, or the database request might have timed out, etc etc. Your current code will misleadingly show "user not found" if there is a database error!
I would also let the Express error handler take care of such real errors, instead of coding error handling for every API function you have:
router.get('/:id', async (req, res, next) => {
checkString(req.params.id);
try {
const person = await peopleData.getPersonById(req.params.id);
res.json(person); // assuming getPersonById returns null if user not found
} catch (e) {
next(e);
});
Your Express error handler, where the invocation of the above next function lands, should be something like this (asssuming router is your Express app):
router.use((err, req, res, next) => {
let statusCode = err.status || 500;
// Assuming your app need to return only json responses
res.json(err);
});
My webpage requires that people log in to access the website. Some pages can only be viewed when a user logs in. For example, here is a route to a profile page that can only be viewed once logged in (express):
router.get('/profile', function (req, res) {
User.findOne({_id: req.user._id}, function (err, user) {
if (err) {
return next(err)
} else {
res.render('main/profile', {user: user});
}
});
});
If someone tries to access the /profile page without logging in, they will get a page with a bunch of errors on it.
What I want to be able to do is, instead of showing a page of random errors, direct these types of users to a proper error page. I've tried replacing return next(err) with something like res.json(You cannot access this page'), but that doesn't seem to be working.
This is the answer to my question, using the link in the comment section above. Basically, when someone tries to access parts of my website without logging in, they will be re-directed to an error page located in the folder errors and the filename 500. And because this specific type of error is a 500 code error, we used res.status(500). here is the complete code (which goes in the main server file):
app.use(function(err, req, res, next) {
res.status(500);
res.render('errors/500');
});
I'm working on a little project - completely new to this stuff - and hope you can help me out.
On the base of this project https://scotch.io/tutorials/build-a-restful-api-using-node-and-express-4 which is up running and works really great.
The main goal is it to send a UserID over the network - which is already working by python/json - and let the server react on this and show a login with the just sent UserID and an password input.
I already enhanced the server.js with a POST from the python script and when the server is running the terminal recognizes when the UserID is sent.
...
router.route('/bears/:id')
.get(function(req, res) {
Bear.find({‚id': req.params.id}, function(err, bear) {
if (err)
res.send(err);
console.log(‚here i am ...');
});
});
...
I also created a HTML which I thought should always listen (by AJAX) to the post and if the trigger (UserId) is send it should forward to another side with the input field.
So right now I don't really know how to implement that the Server already got the trigger and the HTML forwards the User to the Login?
Let the server handle where the user goes - issuing a 200 for a successful user, or an error 400 if it's a bad request. For example:
router.route('/bears/:id')
.get(function(req, res) {
Bear.find({‚id': req.params.id}, function(err, bear) {
if (err)
res.status(400).send(err); //Send a generic bad request error
else {
res.status(200).render('login', { name: req.params.id }); //Direct client to your login page (this example uses the jade template egine)
});
});
I hope this is what you're looking for :)
I'm using Sails.js, and I've installed the passport and passport-local modules, for local authentication.
When I installed the passport module, some files were created automatically, under policies, services, models and controllers. I've modified some of these files to fit my needs, however, I can't find a way to redirect an user to certain location specifically after he registers.
Right now, the default behaviour is that the user registers and is automatically authenticated and then redirected to the same url that an user gets redirected to when he/she logs in.
I've tried to look into the different passport generated files, but I can't find a "registration callback" or something similar. In the AuthController, there's a "callback" method that looks like this:
callback: function (req, res) {
function tryAgain (err) {
var flashError = req.flash('error')[0];
if (err && !flashError ) {
req.flash('error', 'Error.Passport.Generic');
} else if (flashError) {
req.flash('error', flashError);
}
req.flash('form', req.body);
var action = req.param('action');
switch (action) {
case 'register':
res.redirect('/signup');
break;
case 'disconnect':
res.redirect('back');
break;
default:
res.redirect('/login');
}
}
passport.callback(req, res, function (err, user) {
if (err) {
return tryAgain();
}
req.login(user, function (err) {
if (err) {
return tryAgain();
}
res.redirect('/');
});
});
},
However, this only applies to when the user is authenticated (login), I think.
I think the answer may lie under the passport file over at the services folder, but I'm not sure. I don't really fully understand the code yet.
I'm just looking for the right place to even place this code, since I have no clue. So, how can I redirect an user to a specific location after he has registered? (But ONLY after that)
Thanks.
Well, I don't know if this is the best way do to it, but I found it to be quite simple; this is what I did, in case anyone finds themselves under a similar situation with a similar setup.
Under api/services/protocols/local.js, there is a method named exports.register; within that method, and just before next() is called, declare a property isNew to user, like this:
user.isNew = true;
Then, in the callback method of the AuthController, under the controllers folder, isNew will be available (and set to true) as req.user.isNew, if the user just registered, and that way, you can do your logic with that, before res.redirect is called. So, something like this (within that method):
if(req.user.isNew) {
return res.redirect('/welcomePage');
}
return res.redirect('/dashboard');
And that's it.
A web app I'm building will send out invoices to clients every third month. This will be a scheduled event that is run in the middle of the night, but under development I have put this code into a route so I can test it.
In short i want the code to do the following.
QUery all unsent invoices from DB.
Make a call to Mandrill for each invoice (In this call I'm also invoking a function creating a Mandrill message object from the invoice).
For every message Mandrill send, Update the DB invoice sent: true.
When all invoices are sent, make a final callback in the async.waterfall
The code below works. but i have some concerns regarding the _.each.
invoices.post('/invoices/send/', function(req, res, next) {
async.waterfall([
// Query all unsent invoices
function(callback) {
db.invoices.find({sent: false}).toArray(callback);
},
// Send all unsent invoices
function(invoices, callback) {
if (invoices.length === 0) {
var err = new Error('There are no unsent invoices');
err.status = 400;
return next(err); //Quick escape if there are no matching invoice to process
}
// Make a call to Mandrill transactional email service for every invoice.
_.each(invoices, function(invoice) {
mandrillClient.messages.sendTemplate({template_name: "planpal-invoice", template_content: null, message: mandrillClient.createInvoiceMessage(invoice)}, function(sendResult) {
console.log(sendResult);
db.invoices.updateById(invoice._id, {$set: {sent: true}}, function(err, saveResult) {
console.log(saveResult);
});
}, function(err) {
return next(err);
});
});
callback(null, 'done');
}
],
function(err, result) {
if (err) {
return next(err);
}
res.json(result);
});
});
I'm thinking I should use async.eachLimit instead.... but I dont know how to write it.
I have no idea what i should set the limit to, but I guess several parallel request would be better than running all mandrill request in serie like above, am I wrong? EDIT _.each run the callbacks in parallel. The difference from a async.each is that I dont get a "final callback"
Conclusion: Should i use a async.eachLimit above? If Yes, what is a good limit value?
I think you can use the https://github.com/caolan/async#each function.
it will execute the queries in parallel too