How do you limit the number of API requests in Express.js

946 Views Asked by At

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.

0

There are 0 best solutions below