I have a website that I am building. In this website, I am adding Q&A type forums to certain parts of it. I want to allow the users to be able to vote up or down on answers, but limit them to only vote up or down once (but be able to remove/change their vote).
I am using Ajax on the frontend to send the request to the backend. I could add some code to limit it on the frontend, but because frontend code is available to the client, they could easily change that code, so I need to have code in the backend to handle this.
I looked up a bunch of things, and almost all of them were saying to use express-rate-limit library, and do something like this:
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 2000,
max: 1
});
router.post('/route', limiter, ...);
This still doesn't quite work. Sometimes if I click a bunch really fast all those requests are sent, and then something goes wrong and messes up the vote count.
I don't know what to try next. Does anyone know how to fix this?
The following is my backend code to handle the requests:
exports.postVote = (req, res, next) => {
const errors = validationResult(req)
if (!errors.isEmpty()) return res.status(400).json(errors.array()[0].msg)
return Message
.findById(req.body.messageId)
.then((message) => {
if (message.userId.toString() == req.user._id.toString())
return res.status(400).json('You cannot vote on your own post!')
else {
return Vote
.findOne({ userId: req.user._id.toString(), messageId: message._id.toString() })
.then((vote) => {
if (vote) {
if (vote.direction == req.body.direction) {
if (vote.direction == 'up') message.votes--
else if (vote.direction == 'down') message.votes++
else return res.status(500).json('Something didn\'t work out, please try again')
message.save()
vote.remove()
return res.json({ message: 'removed', votes: message.votes })
}
else {
if (req.body.direction == 'up') message.votes+=2
else if (req.body.direction == 'down') message.votes-=2
message.save()
vote.direction = (vote.direction == 'up' ? 'down' : 'up')
vote.save()
return res.json({ message: 'changed', votes: message.votes })
}
}
else {
let messageVote = new Vote({
messageId: message._id,
userId: req.user._id,
direction: req.body.direction
})
if (req.body.direction == 'down') message.votes--
else if (req.body.direction == 'up') message.votes++
else return res.status(500).json('Something didn\'t work out, please try again')
message.save()
messageVote.save()
return res.json({ message: 'added', votes: message.votes })
}
})
.catch(e => {
console.log(e)
return res.status(500).json('Something didn\'t work out, please try again')
})
}
})
.catch(e => {
console.log(e)
return res.status(500).json('Something didn\'t work out, please try again')
})
}
A few of the articles/tutorials I found talked about how the limit only starts once the number of requests goes over the max, is this true? Or does that limiter say that there can only be 1 request every 2 seconds? If it is true, should I say max: 0 (so that it will immediately start limiting the requests)?
Does express-rate-limit actually limit the requests? Or does it just delay requests?
If it limits it, with me limiting it to 1 request every 2 seconds, why does it still mess up?
Any help will be appreciated.