Skip to content

Conversation

@395ShikharSingh
Copy link
Contributor

Closes #118

Rate Limiter for FastAPI Endpoints

Implements comprehensive rate limiting using Nginx limit_req and slowapi to protect the API from overloaded repeated attacks.

Key Features

  • Layered Protection: Nginx blocks at edge, slowapi provides application-level backup
  • Endpoint-Specific Limits:
    • OPDS endpoints: No rate limiting (as requested)
    • /items: No rate limiting (as requested)
    • /upload & /authenticate: Strict (20/min)
    • Other endpoints: General (100/min)
  • TTL Compatible: Both layers use 60-second window

Changes

  • Added slowapi==0.1.9 dependency
  • Created lenny/core/ratelimit.py configuration module
  • Integrated rate limiting into FastAPI app
  • Applied rate limit decorators to 9 endpoints
  • Configured Nginx with 3 rate limit zones
  • Added endpoint-specific location blocks in Nginx

Testing Results

OPDS endpoints: 20/20 requests passed (no rate limiting)
/items endpoint: 20/20 requests passed (no rate limiting)
General endpoints: 11 requests passed, then 503 (rate limited)
Strict endpoints: 8 requests passed, then 503 (rate limited)

Verification

  • slowapi installed and configured:
  • Nginx rate limit zones configured:
  • Both layers working correctly:

PTAL @ronibhakta1

@395ShikharSingh
Copy link
Contributor Author

Removed NGINX rate-limiter logic; kept only SlowAPI rate limiting in this commit

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a comprehensive rate limiting solution for FastAPI endpoints using slowapi, providing layered protection alongside Nginx-level rate limiting to defend against repeated API attacks.

Key Changes:

  • Added slowapi==0.1.9 dependency for application-level rate limiting
  • Created lenny/core/ratelimit.py module with configurable rate limits (general: 100/min, strict: 20/min, lenient: 300/min)
  • Applied rate limit decorators to 9 endpoints with endpoint-specific limits, while keeping OPDS and /items endpoints unrestricted

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 4 comments.

File Description
requirements.txt Added slowapi==0.1.9 dependency for rate limiting functionality
lenny/core/ratelimit.py New module implementing rate limit configuration with environment variable support and FastAPI integration
lenny/app.py Integrated rate limiter initialization into the FastAPI application startup
lenny/routes/api.py Added Request parameters to endpoints and applied rate limit decorators to 9 endpoints (general limits on read/borrow/return operations, strict limits on upload/authenticate)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +21 to +30
def _parse_rate_limit(env_var: str, default: int) -> int:
"""
Parse rate limit from environment variable.
Supports both integer format (100) and string format ('100/minute').
Returns the integer count of requests.
"""
value = os.environ.get(env_var, str(default))
if '/' in str(value):
return int(value.split('/')[0])
return int(value)
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _parse_rate_limit function lacks a return type annotation. Consider adding -> int to the function signature for consistency with type hints and improved code clarity.

Copilot uses AI. Check for mistakes.
# Create the limiter instance
limiter = Limiter(
key_func=get_remote_address,
default_limits=[RATE_LIMIT_GENERAL],
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The limiter is configured with default_limits=[RATE_LIMIT_GENERAL], which applies the general rate limit (100/minute) to all endpoints by default. However, based on the PR description, OPDS endpoints and /items should have no rate limiting. Consider whether this default should be removed (set to []) to explicitly require rate limits on each endpoint, preventing unintended rate limiting on endpoints that should be unrestricted.

Suggested change
default_limits=[RATE_LIMIT_GENERAL],
default_limits=[],

Copilot uses AI. Check for mistakes.
)
from lenny.core.readium import ReadiumAPI
from lenny.core.models import Item
from lenny.core.ratelimit import limiter, RATE_LIMIT_GENERAL, RATE_LIMIT_LENIENT, RATE_LIMIT_STRICT
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RATE_LIMIT_LENIENT is imported but never used in this file. Consider removing it from the import statement to keep the code clean and avoid confusion.

Suggested change
from lenny.core.ratelimit import limiter, RATE_LIMIT_GENERAL, RATE_LIMIT_LENIENT, RATE_LIMIT_STRICT
from lenny.core.ratelimit import limiter, RATE_LIMIT_GENERAL, RATE_LIMIT_STRICT

Copilot uses AI. Check for mistakes.

# Rate limit window in seconds - must be compatible between nginx and slowapi
# Using 60 seconds (1 minute) as a standard window
RATE_LIMIT_WINDOW = int(os.environ.get('RATE_LIMIT_WINDOW', 60))
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RATE_LIMIT_WINDOW is defined but never used anywhere in this module or imported elsewhere. Consider removing it or documenting its intended use case if it's meant for future Nginx configuration compatibility.

Suggested change
RATE_LIMIT_WINDOW = int(os.environ.get('RATE_LIMIT_WINDOW', 60))

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rate limiter for FastAPI endpoints

2 participants