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)