DEV Community

Sami Dghim
Sami Dghim

Posted on

πŸ” Why Your API Needs Rate Limiting ?

If you're running an API β€” whether it powers a mobile app, third-party integrations, or internal tools β€” you're always at risk of misuse.

Sometimes it’s malicious: DDoS attacks, brute-force login attempts, or data scrapers.

Other times, it’s accidental: a buggy client stuck in a loop, or QA testing without throttling.

Either way, without rate limiting, your API becomes a wide-open door for traffic floods that can:

  • πŸ’₯ Overload your servers and databases
  • πŸ’Έ Skyrocket your cloud costs
  • 🐌 Degrade performance for real users
  • πŸ›‘ Expose security vulnerabilities

The good news? There's a simple, proactive defense: Rate Limiting.


🚦 What Is Rate Limiting?

Rate limiting sets a maximum number of requests a client can make to your API within a given time window.

Example: "Each IP can make 100 requests per 10 minutes."

It’s not just about protection β€” it’s also about fairness.

You don’t want one aggressive user (or bot) consuming all your resources while others get timeouts.


πŸ’‘ Why Rate Limiting Matters

βš™οΈ Performance Protection

A sudden burst of requests can queue up, slow down, or even crash your app. Rate limiting prevents this by smoothing out traffic spikes.

πŸ”’ Security Layer

Brute-force attacks, credential stuffing, and scraping become much harder when request volume is capped.

πŸ’° Cost Control

Cloud infrastructure scales with traffic β€” but so do your bills. Preventing junk traffic keeps costs predictable.

βœ… Quality of Service

Legitimate users get consistent, fast responses instead of frustrating timeouts or errors.


❌ Common Mistakes Without Rate Limiting

  • A single misconfigured client breaks the experience for everyone because its loop forgot sleep().
  • Botnets consume all your API capacity during an attack.
  • Your own QA team accidentally triggers a self-inflicted DoS by hammering endpoints without throttling.

πŸ”₯ One uncontrolled script can bring your entire service to its knees.


βœ… Solution 1: Rack::Attack + Redis (Great for Rails APIs)

Rack::Attack is a battle-tested gem for rate limiting in Ruby on Rails apps. Paired with Redis, it scales across multiple servers and handles distributed traffic.

How It Works:

  • Define limits per IP, user token, or endpoint
  • Automatically return 429 Too Many Requests when exceeded
  • Allow safe-lists for health checks or internal services
  • Log and monitor throttled requests for visibility

Setup

# Gemfile
gem "rack-attack"
gem "redis"
Enter fullscreen mode Exit fullscreen mode
# config/application.rb
config.middleware.use Rack::Attack
Enter fullscreen mode Exit fullscreen mode
# config/initializers/rack_attack.rb
Rack::Attack.cache.store = ActiveSupport::Cache::RedisCacheStore.new(url: ENV["REDIS_URL"])

Rack::Attack.throttle("requests per IP", limit: 100, period: 10.minutes) do |req|
  req.ip
end
Enter fullscreen mode Exit fullscreen mode

When the limit is hit, clients receive:

{
  "error": "rate_limited",
  "message": "Too many requests. Please retry later."
}
Enter fullscreen mode Exit fullscreen mode

With HTTP status 429 Too Many Requests.

πŸ’‘ Pro tip: Use custom throttling keys for authenticated users (req.session['user_id']) or API keys.


βœ… Solution 2: Rails 7.2 Built-In Rate Limiting

Starting in Rails 7.2, you can add rate limiting directly in controllers β€” no extra gems needed!

This feature is built into ActionController and uses your existing cache store (Redis, Memcached, or memory).

Example 1: Limit Login Attempts

class SessionsController < ApplicationController
  rate_limit to: 5, within: 1.minute, only: :create
end
Enter fullscreen mode Exit fullscreen mode

Prevents brute-force attacks by limiting login attempts to 5 per minute per session/IP.

Example 2: Limit API Calls Per User

class Api::WidgetsController < ApplicationController
  rate_limit to:     500,
             within: 1.day,
             by:     -> { current_user&.id || request.remote_ip },
             with:   -> { render json: { error: "Rate limit exceeded" }, status: :too_many_requests },
             only:   :index
end
Enter fullscreen mode Exit fullscreen mode

Key Options:

Option Purpose
to: Max number of allowed requests
within: Time window (e.g., 1.hour)
by: Discriminator (user ID, IP, API key)
with: Custom response block when throttled
only: / except: Apply to specific actions

βœ… Perfect for simple, declarative, per-action limits without middleware complexity.


πŸ›‘ Final Thoughts: Rate Limiting = API Armor

Rate limiting isn’t just a performance tweak β€” it’s essential infrastructure hygiene.

It:

  • Prevents single points of failure
  • Defends against common attacks
  • Keeps your cloud costs under control
  • Ensures fair access for all users

Whether you're using Rack::Attack or Rails 7.2’s native tools, adding rate limiting is one of the highest-impact, lowest-effort improvements you can make to your API.

πŸ›  Start small. Protect critical endpoints. Scale as needed.

Your future self will thank you.


πŸ’¬ Have questions?

Are you using rate limiting in production? What strategy works best for your app?

Let me know in the comments πŸ‘‡

rubyonrails #api #security #devops #webdevelopment #backend #rate-limiting #rails7 #redis #tutorial

Top comments (0)