1

I am facing the following problem :

Case 1 (working case) :

file middleware.ts (library for middleware utils functions)

import { NextApiRequest, NextApiResponse } from 'next'
import rateLimit from 'express-rate-limit'

export function runMiddleware(req: NextApiRequest, res: NextApiResponse, fn: Function) {
    return new Promise((resolve, reject) => {
      fn(req, res, (result: any) => {
        if (result instanceof Error) {
          return reject(result)
        }
        return resolve(result)
      })
    })
}

export const limiter = rateLimit({
    keyGenerator: function (req: any) {
        return req.headers["x-forwarded-for"] || req.connection.remoteAddress; 
    }, // Needed because of issue : https://issueexplorer.com/issue/nfriedly/express-rate-limit/254
    windowMs: 60 * 1000, // 1 minute
    max: 5, // 5 requests per IP
})

file login.ts (my API entry point)

import { NextApiRequest, NextApiResponse } from 'next'
import { limiter, runMiddleware } from '../../lib/middleware'

module.exports = async (req: NextApiRequest, res: NextApiResponse) => {


    // Run middlewares
    try {
        await runMiddleware(req, res, limiter)
    } catch {
        res.status(500)
        res.end(JSON.stringify({errorCode: 'unknown', errorValue: ''}))
        return
    }

    if (req.method === 'POST') {
        res.status(200)
        res.end(JSON.stringify({errorCode: 'ok', errorValue: ''}))
    }
}

In this case, if I try more than 5 times to reach my API, I get the message "Too many requests ..." which is what I want.

Case 2 (non-working case) :

file middleware.ts (library for middleware utils functions)

import { NextApiRequest, NextApiResponse } from 'next'

export function runMiddleware(req: NextApiRequest, res: NextApiResponse, fn: Function) {
    return new Promise((resolve, reject) => {
      fn(req, res, (result: any) => {
        if (result instanceof Error) {
          return reject(result)
        }
        return resolve(result)
      })
    })
}

file login.ts (my API entry point)

import { NextApiRequest, NextApiResponse } from 'next'
import rateLimit from 'express-rate-limit'
import { runMiddleware } from '../../lib/middleware'

// Run middlewares
    try {
        const limiter = rateLimit({
            keyGenerator: function (req: any) {
                return req.headers["x-forwarded-for"] || req.connection.remoteAddress; 
            }, // Needed because of issue : https://issueexplorer.com/issue/nfriedly/express-rate-limit/254
            windowMs: 60 * 1000, // 1 minute
            max: 5, // 5 requests per IP
        })
        await runMiddleware(req, res, limiter)
    } catch {
        res.status(500)
        res.end(JSON.stringify({errorCode: 'unknown', errorValue: ''}))
        return
    }

    if (req.method === 'POST') {
        res.status(200)
        res.end(JSON.stringify({errorCode: 'ok', errorValue: ''}))
    }

I don't see the differences between these two cases that could explain how it is not working in my second case. Does someone have an explanation ?

Thanks in advance.

It'sNotMe
  • 1,184
  • 1
  • 9
  • 29
Sylvain
  • 113
  • 1
  • 7
  • 2
    If this is the only difference, then things would still work, so you may need to do a bit more [mcve] work. However, to rule out import side-effects, remove that now-unused `import rateLimit from 'express-rate-limit'` from your middleware file (and maybe set your editor to warn you about unused imports). – Mike 'Pomax' Kamermans Nov 05 '21 at 18:49
  • I updated my question with a minimal reproductible example that has the same behaviour (working in case 1, non-working in case 2) – Sylvain Nov 06 '21 at 11:41
  • 1
    That's because you're declaring and assigning the value to `limiter` on _each_ request, `rateLimit` gets called every time. Try moving the `limiter` declaration outside the handler function. – juliomalves Nov 06 '21 at 16:44

1 Answers1

0

The answer is given in comment by @juliomalves :

"That's because you're declaring and assigning the value to limiter on each request, rateLimit gets called every time. Try moving the limiter declaration outside the handler function."

Sylvain
  • 113
  • 1
  • 7
  • 3
    When taking a comment made by someone else and posting it as an answer, you should consider marking it as a [Community Wiki](https://meta.stackexchange.com/q/11740/616624). You can edit your answer and check the little box, if you would like to do this. – Adrian Mole Nov 07 '21 at 15:25