Rate limiting

A scraper hits your API at a hundred requests per second. Your database starts to struggle. Real users slow down. The scraper is not malicious, just enthusiastic, and it is ruining the experience for everyone. Rate limiting is the tool that stops this without asking you to identify the scraper first.

Where the limiter sits

The limiter runs before auth, before the handler, before the database. If the client is over the limit, the request is rejected with 429 and never touches the rest of the stack.

after/middlewares/rate-limit.ts
typescript
import rateLimit from 'express-rate-limit';

export const generalLimiter = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  limit: 100,          // 100 requests per minute per IP
  standardHeaders: 'draft-7',
  legacyHeaders: false,
  message: { error: 'Too many requests' },
});

// Stricter for auth so brute force has to crawl
export const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  limit: 10,                // 10 login attempts per 15 minutes
  message: { error: 'Too many auth attempts' },
});

A strict limiter for auth endpoints and a looser one for everything else.

after/index.ts
typescript
import { generalLimiter, authLimiter } from './middlewares/rate-limit';

app.use(generalLimiter);

app.post('/api/auth/login', authLimiter, loginHandler);
app.post('/api/auth/register', authLimiter, registerHandler);

Apply the general limiter globally and the auth limiter on the sensitive endpoints.

The second limiter is much stricter than the first. Auth endpoints need it because they are the target of brute force attacks. Ten login attempts per fifteen minutes per IP is generous to real users and crippling to a password grinder. This single pattern prevents an enormous amount of credential abuse.

When the limit is hit, the library responds with 429 Too Many Requests and a Retry-After header that tells the client how long to wait. Real clients respect this and back off. Scrapers and attackers often do not, which is fine: the rate limit is still doing its job by shedding the load.

Quiz: Quiz

Loading practiceโ€ฆ