Skip to content

Conversation

@sujal111
Copy link

@sujal111 sujal111 commented Nov 20, 2025

  • Add fastapi-ratelimiter and redis dependencies
  • Create rate limiter configuration with Redis backend
  • Add test endpoints for rate limiting
  • Update docker-compose.yml with Redis service
  • Add Redis configuration to .env.example

Closes #

📝 Description

🔧 Changes Made

📷 Screenshots or Visual Changes (if applicable)

🤝 Collaboration

Collaborated with: @username (optional)

✅ Checklist

  • I have read the contributing guidelines.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have added necessary documentation (if applicable).
  • Any dependent changes have been merged and published in downstream modules.

Summary by CodeRabbit

Release Notes

  • New Features
    • Rate limiting is now enforced on API endpoints to enhance service stability and fairness
    • Rate limit violations return clear response guidance including retry-after information
    • Support for multiple rate limit strategies: global limits and per-user limits based on authentication

✏️ Tip: You can customize this high-level summary in your review settings.

- Add fastapi-ratelimiter and redis dependencies
- Create rate limiter configuration with Redis backend
- Add test endpoints for rate limiting
- Update docker-compose.yml with Redis service
- Add Redis configuration to .env.example
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 20, 2025

Walkthrough

This pull request adds a Redis-backed rate limiting system to the FastAPI backend. It introduces rate limiter configuration, test endpoints demonstrating different rate limit strategies (unlimited, global, and per-user), integrates the middleware into the app startup, adds required dependencies, and updates Docker Compose to include a Redis service.

Changes

Cohort / File(s) Summary
Rate Limiter Core Infrastructure
backend/app/core/rate_limiter.py
New module configuring Redis-backed rate limiter with default limits (1000/day, 100/hour), custom exception handler returning 429 responses with retry-after headers, user identifier extraction from Bearer tokens or IP addresses, and middleware setup function.
Rate Limit Test Endpoints
backend/app/api/v1/test_rate_limit.py
New APIRouter module with three test endpoints: /unlimited (no limits), /limited (5 req/min global), and /user-limited (10 req/min per-user IP), returning quota and reset time information.
App Integration
backend/main.py
Added Request import, setup_rate_limiter function call, and explicit docs_url/redoc_url parameters to FastAPI instantiation.
Infrastructure & Deployment
backend/docker-compose.yml
Added Redis service (redis:7-alpine) with password protection and persistence, shifted Falkordb ports from 6379→6380 and 3000→3001 to avoid conflicts, and expanded volumes section.
Dependencies
backend/requirements.txt
Added fastapi-ratelimiter==0.4.0 and redis==5.0.1 under new "Rate limiting" section.
Dependency Manifest
backend/minimal-requirements.txt
New file with minimal Python web stack (FastAPI, Uvicorn, Pydantic, SQLAlchemy, redis client, etc.) for lean deployments.
Test Server
backend/test_server.py
New standalone minimal FastAPI app with single GET / endpoint returning a status message and uvicorn runner.

Sequence Diagrams

sequenceDiagram
    participant Client
    participant FastAPI as FastAPI App
    participant RateLimitMiddleware
    participant Redis
    participant Endpoint

    Client->>FastAPI: HTTP Request
    FastAPI->>RateLimitMiddleware: Process via middleware
    RateLimitMiddleware->>RateLimitMiddleware: Extract user identifier<br/>(Bearer token or IP)
    RateLimitMiddleware->>Redis: Check/increment quota<br/>for identifier
    alt Limit Exceeded
        Redis-->>RateLimitMiddleware: RateLimitExceeded
        RateLimitMiddleware-->>Client: 429 JSON<br/>(with retry-after)
    else Within Limit
        Redis-->>RateLimitMiddleware: OK + quota info
        RateLimitMiddleware->>Endpoint: Pass request.state<br/>with quota details
        Endpoint-->>Client: 200 + response
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas requiring attention:
    • backend/app/core/rate_limiter.py: Review Redis configuration, authentication handling, and exception handler logic for edge cases
    • backend/app/api/v1/test_rate_limit.py: Verify rate limit values and key extraction logic for per-user limiting
    • backend/docker-compose.yml: Confirm Redis persistence settings, healthcheck reliability, and port collision resolution
    • backend/main.py: Ensure middleware is applied at correct app initialization phase

Poem

🐰 A redis bouncer hops into town,
Counting requests up and down,
"Five per minute?" the rabbit declares,
With distributed fairness, no one despairs!
🚀 Rate limits dance, the system takes flight! ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: implement rate limiting with Redis' accurately and concisely describes the main change—adding rate limiting functionality backed by Redis. It directly aligns with the core objectives and the primary modifications across multiple files.
Docstring Coverage ✅ Passed Docstring coverage is 87.50% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (6)
backend/test_server.py (1)

10-11: Be cautious about binding the test server to all interfaces

Using host="0.0.0.0" is fine for local dev or inside Docker, but if someone runs this script directly on a machine it will expose the server on all interfaces. If you ever use this outside a container, consider switching to 127.0.0.1 or gating the host via an environment variable.

As per static analysis hints.

backend/minimal-requirements.txt (1)

1-15: Remove duplicate packages and clarify version strategy vs main requirements

This minimal requirements file contains several duplicates (python-multipart, python-jose[cryptography], python-dotenv), which are harmless but add noise. It’d be cleaner to keep each package only once.

Also, versions here (e.g., fastapi==0.109.2) differ from backend/requirements.txt (which pins a newer FastAPI). If this file is used for any real runtime or CI image, consider aligning versions or documenting that this is a separate, intentionally different “minimal stack” to avoid subtle incompatibilities.

backend/main.py (1)

7-9: Rate limiter setup is correctly wired; confirm that global default limits are desired

Calling setup_rate_limiter(api) immediately after creating the FastAPI app is a good place to attach middleware and the exception handler. Note that with your current RateLimiter configuration (default_limits=["1000 per day", "100 per hour"] in app/core/rate_limiter.py), those limits will apply to all routes, in addition to any per‑route @rate_limiter.limit decorators (depending on library semantics).

If you only want explicit endpoints (like the /test ones) to be limited, consider making the global defaults configurable (via settings) or disabling them and relying solely on per‑route limits.

Also applies to: 106-110

backend/app/api/v1/test_rate_limit.py (1)

4-29: Gate /test endpoints to non‑production and consider reusing the user ID helper

These endpoints are great for validating the rate limiter, but exposing /test/* in production could leak implementation details and invite unnecessary probing. Consider only including this router when a debug/development flag is enabled.

For /user-limited, the current key function is effectively per‑IP. If you later move to authenticated users, it’d be cleaner to reuse a shared helper like get_user_identifier(request) (from app.core.rate_limiter) to keep the “who is this request counted against?” logic in one place.

backend/app/core/rate_limiter.py (2)

8-15: Redis settings defaults are reasonable; ensure REDIS_HOST is set correctly in Docker

The RedisSettings defaults (localhost:6379, db 0, optional SSL) are fine for local, non-containerized runs. Inside your Docker Compose setup, though, the backend container will need REDIS_HOST set to the Redis service name (likely redis), otherwise the default "localhost" will point back to the app container instead of the Redis one.

Double‑check that your .env / compose environment exports REDIS_HOST=redis (and the correct REDIS_PORT, REDIS_DB, and REDIS_SSL) so this configuration works consistently across dev and prod.


36-46: Clarify get_user_identifier semantics or derive a stable user ID from JWT

The docstring says this extracts a “user identifier,” but the implementation uses the first 8 chars of the raw Bearer token and otherwise falls back to IP. That’s fine for a simple demo, but it won’t give a stable per-user key if tokens rotate, and it isn’t actually decoding any JWT or session.

Either update the docstring to describe the current behavior (token-prefix/IP-based key) or, if you intend true per-user limits, decode the JWT and use a stable claim (e.g., sub or user_id) here, then reuse this helper in your route key_funcs.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8eeacad and 21ed94c.

📒 Files selected for processing (7)
  • backend/app/api/v1/test_rate_limit.py (1 hunks)
  • backend/app/core/rate_limiter.py (1 hunks)
  • backend/docker-compose.yml (2 hunks)
  • backend/main.py (2 hunks)
  • backend/minimal-requirements.txt (1 hunks)
  • backend/requirements.txt (1 hunks)
  • backend/test_server.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
backend/main.py (1)
backend/app/core/rate_limiter.py (1)
  • setup_rate_limiter (48-55)
🪛 Ruff (0.14.5)
backend/test_server.py

11-11: Possible binding to all interfaces

(S104)

backend/app/core/rate_limiter.py

25-25: Unused function argument: request

(ARG001)

🔇 Additional comments (2)
backend/requirements.txt (1)

233-236: Redis + fastapi-ratelimiter deps look consistent with the new rate-limiting feature

The new pinned dependencies fit the Redis-backed rate limiter you’ve added. Just make sure every deployment path (Docker image, CI, any “minimal” env using a different requirements file) installs these so imports of fastapi_ratelimiter / redis never fail at runtime.

backend/app/core/rate_limiter.py (1)

25-35: I'll verify the key claims in this review comment by searching for information about Ruff's ARG001 rule and FastAPI exception handler requirements.

Based on my verification of the review comment, the analysis is correct:

Ruff's ARG001 checks for the presence of unused arguments in function definitions. The suggestion to rename the parameter is valid because if a variable is intentionally defined-but-not-used, it should be prefixed with an underscore to adhere to the lint.dummy-variable-rgx pattern. In fact, Ruff does not raise ARG001 when an argument name matches the dummy-variable-rgx pattern, which typically matches names starting with underscore.

For FastAPI specifically, exception handlers receive a Request and the exception, and renaming the unused parameter to _request is a standard practice that maintains the required handler signature while satisfying the linter. The code snippet correctly shows that only exc.retry_after is used from the exception object.

The refactoring suggestion is sound and follows established conventions.


Comment on lines +44 to +58
redis:
image: redis:7-alpine
container_name: redis
ports:
- '6379:6379'
volumes:
- redis_data:/data
command: redis-server --requirepass ${REDIS_PASSWORD:-your_secure_password} --appendonly yes
restart: always
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 30s
retries: 3

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix Redis password default to avoid auth mismatch and weak default

The new Redis service wiring and decoupling Falkordb ports look good, but this line is risky:

command: redis-server --requirepass ${REDIS_PASSWORD:-your_secure_password} --appendonly yes

If REDIS_PASSWORD isn’t set, Redis will require your_secure_password while app.core.rate_limiter.redis_settings will try connecting with no password, causing auth failures and leaving an extremely weak default secret in any environment that forgets to set it.

Consider instead requiring the env var explicitly:

-    command: redis-server --requirepass ${REDIS_PASSWORD:-your_secure_password} --appendonly yes
+    command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes

and ensure REDIS_PASSWORD is always set via .env / secrets for both Redis and the backend. Also double‑check that REDIS_HOST for the app is set to the service name redis so connections work correctly in this compose network.

Also applies to: 63-64, 78-79

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.

1 participant