Isaac.

web

Implementing Rate Limiting

Protect endpoints from abuse with rate limiting strategies.

By Emem IsaacJune 24, 20232 min read
#rate limiting#api protection#middleware#throttling
Share:

A Simple Analogy

Rate limiting is like a speed limit on highways. It prevents abuse by restricting how fast (many requests) can happen.


Why Rate Limiting?

  • Abuse prevention: Block malicious clients
  • Resource protection: Don't overload servers
  • Fair access: Prevent monopolization
  • Cost control: Limit API usage costs
  • DoS protection: Mitigate attacks

Per-IP Rate Limiting

public class IpRateLimitMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ConcurrentDictionary<string, RateLimit> _limits;
    
    public IpRateLimitMiddleware(RequestDelegate next)
    {
        _next = next;
        _limits = new ConcurrentDictionary<string, RateLimit>();
    }
    
    public async Task InvokeAsync(HttpContext context)
    {
        var ip = context.Connection.RemoteIpAddress.ToString();
        var limit = _limits.GetOrAdd(ip, _ => new RateLimit(100, TimeSpan.FromMinutes(1)));
        
        if (!limit.IsAllowed())
        {
            context.Response.StatusCode = 429;
            context.Response.Headers.Add("Retry-After", "60");
            await context.Response.WriteAsync("Rate limit exceeded");
            return;
        }
        
        await _next(context);
    }
    
    public class RateLimit
    {
        private int _remaining;
        private DateTime _resetTime;
        
        public RateLimit(int limit, TimeSpan window)
        {
            _remaining = limit;
            _resetTime = DateTime.UtcNow.Add(window);
        }
        
        public bool IsAllowed()
        {
            if (DateTime.UtcNow >= _resetTime)
            {
                _remaining = 100;
                _resetTime = DateTime.UtcNow.AddMinutes(1);
            }
            
            if (_remaining > 0)
            {
                _remaining--;
                return true;
            }
            
            return false;
        }
    }
}

Header-Based Response

context.Response.Headers.Add("X-RateLimit-Limit", "100");
context.Response.Headers.Add("X-RateLimit-Remaining", "45");
context.Response.Headers.Add("X-RateLimit-Reset", "1645000000");

// Or
context.Response.Headers.Add("Retry-After", "60");  // seconds to wait

Sliding Window

public class SlidingWindowCounter
{
    private readonly Queue<DateTime> _requests = new();
    private readonly int _limit;
    private readonly TimeSpan _window;
    
    public SlidingWindowCounter(int limit, TimeSpan window)
    {
        _limit = limit;
        _window = window;
    }
    
    public bool IsAllowed()
    {
        var now = DateTime.UtcNow;
        var cutoff = now.Subtract(_window);
        
        // Remove old requests
        while (_requests.Count > 0 && _requests.Peek() < cutoff)
        {
            _requests.Dequeue();
        }
        
        if (_requests.Count < _limit)
        {
            _requests.Enqueue(now);
            return true;
        }
        
        return false;
    }
}

Endpoint-Specific Limits

[RateLimit(limit: 100, window: 60)]  // 100 requests per 60 seconds
[HttpGet("products")]
public async Task<IActionResult> GetProducts()
{
    return Ok(await _service.GetProductsAsync());
}

[RateLimit(limit: 10, window: 60)]  // Stricter for writes
[HttpPost("products")]
public async Task<IActionResult> CreateProduct(CreateProductRequest req)
{
    var product = await _service.CreateAsync(req);
    return CreatedAtAction(nameof(GetProducts), new { id = product.Id });
}

Best Practices

  1. Be generous: Don't limit legitimate users
  2. Inform clients: Use headers clearly
  3. Transparent: Document limits in API docs
  4. Graceful degradation: Queue instead of reject
  5. Monitor: Track limit violations

Related Concepts

  • Quota management
  • Throttling
  • Traffic shaping
  • DDoS protection

Summary

Implement rate limiting to protect endpoints from abuse. Use per-IP tracking, sliding windows, and clear response headers.

Share:

Written by Emem Isaac

Expert Software Engineer with 15+ years of experience building scalable enterprise applications. Specialized in ASP.NET Core, Azure, Docker, and modern web development. Passionate about sharing knowledge and helping developers grow.

Ready to Build Something Amazing?

Let's discuss your project and explore how my expertise can help you achieve your goals. Free consultation available.

💼 Trusted by 50+ companies worldwide | ⚡ Average response time: 24 hours