<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: zlynv</title>
    <description>The latest articles on DEV Community by zlynv (@zlynv).</description>
    <link>https://dev.to/zlynv</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4052266%2F7b17d90f-0f9b-4548-921b-22e79ea6739a.png</url>
      <title>DEV Community: zlynv</title>
      <link>https://dev.to/zlynv</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zlynv"/>
    <language>en</language>
    <item>
      <title>Every Python rate limiter has this DDoS blind spot — I built one that doesn't</title>
      <dc:creator>zlynv</dc:creator>
      <pubDate>Sun, 02 Aug 2026 11:45:25 +0000</pubDate>
      <link>https://dev.to/zlynv/every-python-rate-limiter-has-this-ddos-blind-spot-i-built-one-that-doesnt-1260</link>
      <guid>https://dev.to/zlynv/every-python-rate-limiter-has-this-ddos-blind-spot-i-built-one-that-doesnt-1260</guid>
      <description>&lt;h1&gt;
  
  
  Every Python rate limiter has this DDoS blind spot — I built one that doesn't
&lt;/h1&gt;

&lt;p&gt;10,000 bots hit your API. Each one sends exactly 1 request per minute. Every single bot is under your rate limit. Your &lt;code&gt;slowapi&lt;/code&gt; or &lt;code&gt;flask-limiter&lt;/code&gt; sees nothing wrong.&lt;/p&gt;

&lt;p&gt;But your server is drowning.&lt;/p&gt;

&lt;p&gt;I discovered this the hard way. After deploying slowapi in production for 6 months, I realized it had a fundamental blind spot: &lt;strong&gt;it counts requests, but it doesn't detect attacks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://github.com/zlynv/drogue" rel="noopener noreferrer"&gt;drogue&lt;/a&gt; — and tested it under real DDoS traffic.&lt;/p&gt;




&lt;h2&gt;
  
  
  The blind spot
&lt;/h2&gt;

&lt;p&gt;Every rate limiter I tested works the same way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This catches overuse. It doesn't catch distributed attacks.
&lt;/span&gt;&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/api/data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@limiter.limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;100/minute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_data&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem: &lt;strong&gt;rate limiting and DDoS detection are different problems.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rate limiting&lt;/strong&gt; catches single clients exceeding limits. It misses distributed attacks where each client stays under the limit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DDoS detection&lt;/strong&gt; catches anomalous traffic patterns. It's a different layer entirely.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most Python libraries only solve the first one. I needed both.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I tested
&lt;/h2&gt;

&lt;p&gt;I benchmarked 5 rate limiting approaches under simulated DDoS traffic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;slowapi&lt;/strong&gt;: Rate limiting only. No DDoS detection. No WebSocket support.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;flask-limiter&lt;/strong&gt;: Rate limiting only. Flask-specific. No DDoS detection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pyrate-limiter&lt;/strong&gt;: Rate limiting only. Algorithm-focused. No framework adapters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ratethrottle&lt;/strong&gt;: Rate limiting + DDoS detection + WebSocket support. No trust system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;drogue&lt;/strong&gt;: Rate limiting + DDoS detection + WebSocket support + trust state machine + circuit breaker.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key difference: drogue has a &lt;strong&gt;Z-score anomaly detector&lt;/strong&gt; that learns what "normal" traffic looks like and flags statistical outliers.&lt;/p&gt;




&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;drogue adds two layers that rate limiters miss:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Z-score anomaly detection&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This tracks request rates per client and compares each client against the distribution of all client rates. When a client's rate deviates significantly from peers, it gets blocked. A client sending 5x more than the average gets flagged.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Progressive bans&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After 5 violations, bans escalate automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Level 1: 1 minute&lt;/li&gt;
&lt;li&gt;Level 2: 10 minutes&lt;/li&gt;
&lt;li&gt;Level 3: 1 hour&lt;/li&gt;
&lt;li&gt;Level 4: 24 hours&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Most libraries only count requests. drogue detects attacks.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The results
&lt;/h2&gt;

&lt;p&gt;I ran a DDoS simulation with 50 concurrent users (mix of normal users and attackers):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Total requests&lt;/td&gt;
&lt;td&gt;42,815&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Requests/sec&lt;/td&gt;
&lt;td&gt;2,173.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Attackers banned (403)&lt;/td&gt;
&lt;td&gt;97.8% of attacker traffic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rate limited (429)&lt;/td&gt;
&lt;td&gt;0.02%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Successful attacks&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;97.8% of requests from attackers were banned.&lt;/strong&gt; The remaining 2.2% were legitimate traffic that passed through. Note: this is the combined result of anomaly detection, progressive bans, and endpoint rate limits working together, not the anomaly detector alone.&lt;/p&gt;

&lt;p&gt;Response time overhead: p50=5ms, p95=7ms, p99=10ms. Less than 10ms for most applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  The feature comparison
&lt;/h2&gt;

&lt;p&gt;Here's what drogue includes that others don't:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;drogue&lt;/th&gt;
&lt;th&gt;slowapi&lt;/th&gt;
&lt;th&gt;flask-limiter&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DDoS detection&lt;/td&gt;
&lt;td&gt;Z-score&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Progressive bans&lt;/td&gt;
&lt;td&gt;Auto-escalating&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trust state machine&lt;/td&gt;
&lt;td&gt;7 states&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebSocket protection&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Circuit breaker&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5 algorithms&lt;/td&gt;
&lt;td&gt;TB/SW/FW/GCRA/LB&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Framework support&lt;/td&gt;
&lt;td&gt;FastAPI/Django/Flask/DRF&lt;/td&gt;
&lt;td&gt;FastAPI&lt;/td&gt;
&lt;td&gt;Flask&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  What I got wrong
&lt;/h2&gt;

&lt;p&gt;My first attempt was simple: blacklist IPs that hit the endpoint too many times. It didn't work. Attackers rotate IPs every few minutes. By the time I banned one IP, they had already moved to another.&lt;/p&gt;

&lt;p&gt;My second attempt: set a threshold of 1,000 requests per minute. If a client exceeds it, ban them. This also failed. The attack was distributed across 50,000 IPs. Each one was sending only 10 requests per minute. Every single bot was under the threshold.&lt;/p&gt;

&lt;p&gt;The lesson: we can't catch a distributed attack with threshold-based rules. We need cross-sectional comparison across clients.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where drogue is today&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;drogue's Z-score detector compares each client's rate against the distribution of all client rates. A client sending 5x more than peers gets flagged. This catches bursty attackers who stand out from normal traffic.&lt;/p&gt;

&lt;p&gt;But it doesn't catch everything. If 50,000 bots each send exactly the same rate, no one is an outlier. And if attackers rotate IPs, bans don't follow them. These are hard problems that need browser fingerprinting and global traffic analysis, neither of which drogue does yet.&lt;/p&gt;

&lt;p&gt;The core insight still holds: rate limiting alone isn't enough. But drogue is a step toward better protection, not a complete solution.&lt;/p&gt;




&lt;h2&gt;
  
  
  The counterintuitive truth
&lt;/h2&gt;

&lt;p&gt;The fastest rate limiter isn't the best one.&lt;/p&gt;

&lt;p&gt;drogue is slower than slowapi. 5ms overhead vs 2ms. That's a 2.5x difference. In benchmarks, slowapi wins.&lt;/p&gt;

&lt;p&gt;But slowapi doesn't detect DDoS attacks. It doesn't ban attackers. It doesn't learn what "normal" traffic looks like.&lt;/p&gt;

&lt;p&gt;Protection isn't about speed. It's about coverage.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;drogue[fastapi]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;drogue.adapters.fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DrogueLimiter&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;limiter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DrogueLimiter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default_limits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;100/minute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/api/data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@limiter.limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10/minute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_data&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. No &lt;code&gt;request: Request&lt;/code&gt;. No configuration files. DDoS protection built in.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;drogue v0.2.0 is out now with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GCRA + Leaky Bucket algorithms&lt;/li&gt;
&lt;li&gt;MongoDB storage backend&lt;/li&gt;
&lt;li&gt;Thread safety guarantees&lt;/li&gt;
&lt;li&gt;Full benchmark suite&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;v0.3&lt;/strong&gt; will add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Redis-backed ban persistence&lt;/li&gt;
&lt;li&gt;Trust cache sync across workers&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Try it out
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/zlynv/drogue" rel="noopener noreferrer"&gt;github.com/zlynv/drogue&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PyPI&lt;/strong&gt;: &lt;a href="https://pypi.org/project/drogue/" rel="noopener noreferrer"&gt;pypi.org/project/drogue&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs&lt;/strong&gt;: &lt;a href="https://zlynv.github.io/drogue/" rel="noopener noreferrer"&gt;zlynv.github.io/drogue&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Have you been hit by a distributed attack that your rate limiter missed? I'd love to hear about it in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>security</category>
    </item>
    <item>
      <title>Building a Modern Rate Limiter and DDoS Protection Library for Python</title>
      <dc:creator>zlynv</dc:creator>
      <pubDate>Wed, 29 Jul 2026 03:31:10 +0000</pubDate>
      <link>https://dev.to/zlynv/building-a-modern-rate-limiter-and-ddos-protection-library-for-python-49fe</link>
      <guid>https://dev.to/zlynv/building-a-modern-rate-limiter-and-ddos-protection-library-for-python-49fe</guid>
      <description>&lt;p&gt;Rate limiting is one of those features every production API eventually needs.&lt;/p&gt;

&lt;p&gt;Whether you're building a public REST API, a WebSocket service, or an authentication endpoint, you'll eventually face problems like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Credential stuffing&lt;/li&gt;
&lt;li&gt;Brute-force attacks&lt;/li&gt;
&lt;li&gt;API abuse&lt;/li&gt;
&lt;li&gt;Bots scraping your endpoints&lt;/li&gt;
&lt;li&gt;Unexpected traffic spikes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most applications solve this with a simple request counter.&lt;/p&gt;

&lt;p&gt;But after building several APIs with Django, FastAPI, and Flask, I realized that production traffic requires much more than "X requests per minute."&lt;/p&gt;

&lt;p&gt;That observation led me to build &lt;strong&gt;drogue&lt;/strong&gt;, an open-source Python library for rate limiting and traffic protection.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Traditional rate limiting is straightforward:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Allow 100 requests per minute.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This works well for many cases, but real-world applications quickly expose its limitations.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A distributed attack can remain below the per-IP limit.&lt;/li&gt;
&lt;li&gt;A bot can rotate through proxies.&lt;/li&gt;
&lt;li&gt;WebSocket connections often require different handling than HTTP requests.&lt;/li&gt;
&lt;li&gt;Different endpoints need different protection strategies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted a system that could go beyond simple request counting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design Goals
&lt;/h2&gt;

&lt;p&gt;From the beginning, I focused on a few principles.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Clean framework integration
&lt;/h3&gt;

&lt;p&gt;I didn't want endpoint functions filled with framework-specific plumbing.&lt;/p&gt;

&lt;p&gt;Instead, the library should feel like a natural extension of the framework.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;drogue.adapters.fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DrogueLimiter&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;limiter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DrogueLimiter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default_limits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;100/minute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/users&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@limiter.limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10/minute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;users&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ok&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No additional request objects.&lt;br&gt;
No complicated middleware configuration.&lt;br&gt;
Minimal boilerplate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multiple Rate Limiting Algorithms
&lt;/h2&gt;

&lt;p&gt;Different applications require different algorithms.&lt;/p&gt;

&lt;p&gt;Instead of supporting only one approach, drogue includes multiple options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Token Bucket&lt;/li&gt;
&lt;li&gt;Sliding Window&lt;/li&gt;
&lt;li&gt;Fixed Window&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each has different trade-offs between accuracy, burst handling, and memory usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond Rate Limiting
&lt;/h2&gt;

&lt;p&gt;One thing I kept noticing was that abusive traffic often doesn't violate the configured limits.&lt;/p&gt;

&lt;p&gt;An attacker may intentionally stay below the threshold.&lt;/p&gt;

&lt;p&gt;That's why I started experimenting with additional protection mechanisms such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Traffic anomaly detection&lt;/li&gt;
&lt;li&gt;Progressive temporary bans&lt;/li&gt;
&lt;li&gt;Probe detection&lt;/li&gt;
&lt;li&gt;Circuit breakers&lt;/li&gt;
&lt;li&gt;CIDR filtering&lt;/li&gt;
&lt;li&gt;Shadow mode for safely testing rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rather than replacing traditional rate limiting, these features complement it.&lt;/p&gt;

&lt;h2&gt;
  
  
  WebSocket Support
&lt;/h2&gt;

&lt;p&gt;Many existing rate limiting solutions primarily focus on HTTP.&lt;/p&gt;

&lt;p&gt;Modern applications increasingly rely on WebSockets for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chat applications&lt;/li&gt;
&lt;li&gt;Live dashboards&lt;/li&gt;
&lt;li&gt;Multiplayer games&lt;/li&gt;
&lt;li&gt;Real-time notifications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Supporting both HTTP and WebSocket traffic from the same library became an important design goal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Framework Support
&lt;/h2&gt;

&lt;p&gt;Currently, drogue provides adapters for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Django&lt;/li&gt;
&lt;li&gt;Django REST Framework&lt;/li&gt;
&lt;li&gt;FastAPI&lt;/li&gt;
&lt;li&gt;Flask&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is to keep the developer experience as consistent as possible across frameworks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Performance matters because rate limiting runs on every request.&lt;/p&gt;

&lt;p&gt;The core package is designed with minimal overhead while keeping the implementation extensible enough for different storage backends and deployment scenarios.&lt;/p&gt;

&lt;p&gt;Performance testing and optimization remain an ongoing part of development, and I plan to continue publishing benchmark improvements as the project evolves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;Building this project taught me several things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Good APIs are often harder to design than efficient algorithms.&lt;/li&gt;
&lt;li&gt;Framework integration significantly affects developer experience.&lt;/li&gt;
&lt;li&gt;Rate limiting alone isn't enough for many production environments.&lt;/li&gt;
&lt;li&gt;Clear documentation is just as important as clean code.&lt;/li&gt;
&lt;li&gt;Simplicity usually wins over feature overload.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;There are still many ideas I'd like to explore, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Additional storage backends&lt;/li&gt;
&lt;li&gt;More adaptive protection strategies&lt;/li&gt;
&lt;li&gt;Better observability&lt;/li&gt;
&lt;li&gt;Additional framework integrations&lt;/li&gt;
&lt;li&gt;More comprehensive benchmarking&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  I'd Love Your Feedback
&lt;/h2&gt;

&lt;p&gt;This project is still evolving, and feedback from the Python community is incredibly valuable.&lt;/p&gt;

&lt;p&gt;If you build production APIs with Django, FastAPI, Flask, or another Python framework, I'd love to hear your thoughts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What features do you look for in a rate limiting library?&lt;/li&gt;
&lt;li&gt;What challenges have you encountered protecting public APIs?&lt;/li&gt;
&lt;li&gt;Is there something missing that would make a library like this more useful?&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;The project is open source, and contributions, suggestions, and constructive criticism are always welcome.&lt;/p&gt;

&lt;p&gt;Building infrastructure libraries is always a balancing act between performance, flexibility, and developer experience. Drogue is my attempt to make API protection easier without sacrificing clean application code.&lt;/p&gt;

&lt;p&gt;If you're building production APIs with Django, FastAPI, Flask, or another Python framework, I'd love to hear your thoughts. Whether it's an issue, feature request, benchmark, or pull request, your feedback will help shape the project.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/zlynv/drogue" rel="noopener noreferrer"&gt;https://github.com/zlynv/drogue&lt;/a&gt;&lt;br&gt;
Documentation: &lt;a href="https://zlynv.github.io/drogue/" rel="noopener noreferrer"&gt;https://zlynv.github.io/drogue/&lt;/a&gt;&lt;br&gt;
PyPI: &lt;code&gt;pip install drogue&lt;/code&gt;&lt;/p&gt;

</description>
      <category>fastapi</category>
      <category>django</category>
      <category>flask</category>
      <category>python</category>
    </item>
  </channel>
</rss>
