Rate Limiting

Protect your APIs from abuse and ensure fair usage with MoroJS's built-in rate limiting capabilities. Configure limits per user, IP, or custom keys.

Basic Rate Limiting

Route-Level Rate Limiting (Chainable API)

typescript

1import { createApp, z, validate } from '@morojs/moro';
2
3const app = createApp();
4
5// Rate limiting with chainable API
6app.post('/users')
7  .body(z.object({
8    name: z.string().min(2).max(50),
9    email: z.string().email()
10  }))
11  .rateLimit({ requests: 10, window: 60000 }) // 10 requests per minute
12  .handler((req, res) => {
13    const newUser = {
14      id: Date.now(),
15      ...req.body
16    };
17    
18    res.status(201);
19    return { 
20      success: true, 
21      data: newUser,
22      message: 'User created successfully!'
23    };
24  });
25
26// Different limits for different endpoints
27app.post('/auth/login')
28  .body(z.object({
29    email: z.string().email(),
30    password: z.string()
31  }))
32  .rateLimit({ requests: 5, window: 900000 }) // 5 attempts per 15 minutes
33  .handler((req, res) => {
34    return authenticateUser(req.body);
35  });
36
37// Schema-first approach with rate limiting
38app.route({
39  method: 'POST',
40  path: '/api/signup',
41  validation: {
42    body: z.object({
43      email: z.string().email(),
44      password: z.string().min(8)
45    })
46  },
47  rateLimit: { requests: 3, window: 3600000 }, // 3 signups per hour
48  handler: (req, res) => {
49    return createUser(req.body);
50  }
51});

Application Configuration

typescript

1import { createApp } from '@morojs/moro';
2
3// Basic app configuration (rate limiting is per-route)
4const app = createApp({
5  cors: true,
6  compression: true,
7  helmet: true
8});
9
10// Rate limiting is applied per route using chainable API
11app.get('/users')
12  .rateLimit({ requests: 100, window: 60000 }) // 100 requests per minute
13  .handler((req, res) => {
14    return getUsers();
15  });
16
17// Higher limits for public endpoints
18app.get('/api/public')
19  .rateLimit({ requests: 1000, window: 3600000 }) // 1000 requests per hour
20  .handler(() => getPublicData());
21
22// Configuration-driven rate limiting
23app.post('/users-config')
24  .rateLimit({ 
25    requests: app.getConfig().modules.rateLimit.defaultRequests, 
26    window: app.getConfig().modules.rateLimit.defaultWindow 
27  })
28  .handler((req, res) => {
29    return createUser(req.body);
30  });

Advanced Configuration

Custom Rate Limit Keys

typescript

1// Rate limit by user ID
2app.get('/api/user-data', {
3  middleware: [
4    authMiddleware,
5    {
6      rateLimit: {
7        max: 1000,
8        window: '1h',
9        key: (ctx) => `user:${ctx.context.user.id}`
10      }
11    }
12  ],
13  handler: ({ context }) => {
14    return getUserData(context.user.id);
15  }
16});
17
18// Rate limit by API key
19app.get('/api/premium', {
20  middleware: [
21    {
22      rateLimit: {
23        max: (ctx) => {
24          // Different limits based on subscription
25          const apiKey = ctx.headers['x-api-key'];
26          const user = getUserByApiKey(apiKey);
27          return user.plan === 'premium' ? 10000 : 1000;
28        },
29        window: '1h',
30        key: (ctx) => `apikey:${ctx.headers['x-api-key']}`
31      }
32    }
33  ],
34  handler: () => getPremiumData()
35});

Custom Error Responses

typescript

1app.post('/api/sensitive', {
2  middleware: [
3    {
4      rateLimit: {
5        max: 10,
6        window: '1h',
7        key: 'ip',
8        onLimitReached: (ctx, info) => {
9          // Custom error response
10          return {
11            status: 429,
12            headers: {
13              'Retry-After': info.resetTime.toString(),
14              'X-RateLimit-Limit': info.limit.toString(),
15              'X-RateLimit-Remaining': '0',
16              'X-RateLimit-Reset': info.resetTime.toString()
17            },
18            body: {
19              error: 'RATE_LIMIT_EXCEEDED',
20              message: `Too many requests. Try again in ${info.resetTime} seconds.`,
21              retryAfter: info.resetTime
22            }
23          };
24        }
25      }
26    }
27  ],
28  handler: () => processSensitiveData()
29});

Rate Limiting Strategies

Common Patterns

  • Authentication: 5 attempts per 15 minutes
  • API calls: 1000 requests per hour
  • File uploads: 10 uploads per hour
  • Password reset: 3 attempts per hour

Best Practices

  • Use appropriate time windows
  • Provide clear error messages
  • Include retry-after headers
  • Monitor and adjust limits

Next Steps