Skip to content

fix(api): enforce route-level rate limits#573

Merged
knoxiboy merged 2 commits into
knoxiboy:mainfrom
eshaanag:fix/api-route-rate-limits
Jun 27, 2026
Merged

fix(api): enforce route-level rate limits#573
knoxiboy merged 2 commits into
knoxiboy:mainfrom
eshaanag:fix/api-route-rate-limits

Conversation

@eshaanag

@eshaanag eshaanag commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

User description

Fixes #506

Summary

  • add a shared route-level rate-limit helper with normalized authenticated-email keys
  • return consistent 429 responses with Retry-After and rate-limit headers
  • apply AI, general-write, and video limiters to the assigned expensive/mutation endpoints
  • cover the actual bookmark mutation route; /api/bookmarks remains read-only
  • fail closed for AI/video limiter outages and preserve general-route availability

Validation

  • focused rate-limit and Ask AI tests: 6/6 passing
  • full Jest suite: 20/23 suites, 91/96 tests passing; the five failures match upstream main (room-members, doubt sorting/filtering, DB config)
  • git diff --check: passed
  • local TypeScript check remains blocked by merge-conflict markers already present on upstream main in karma files

Summary by CodeRabbit

  • New Features

    • Per-user API rate limits added across AI, video, and general endpoints with early checks returning 429 responses, Retry-After and rate-limit headers, and category-specific messages; a centralized enforcement helper standardizes behavior.
    • Middleware refined to target which public API routes are limited and to vary failure behavior by category.
  • Tests

    • Expanded/updated tests for enforcement, headers, message shapes, identifier normalization, and fail-open vs fail-closed behaviors.
  • Chores

    • Test setup adds mocks for rate-limiters and client utilities.

CodeAnt-AI Description

Apply route-level rate limits to AI, video, and write actions

What Changed

  • AI, video, and other write actions now stop with a 429 before doing extra work once a user reaches their limit.
  • Rate-limited responses now include retry timing and limit details, along with a clear message for the blocked action.
  • Signed-in users are counted under the same email address across requests, so the same person is limited consistently.
  • If rate limiting fails on AI or video routes, those requests now return a service-unavailable error instead of continuing.
  • Bookmark actions are no longer rate-limited through the public middleware, and the actual bookmark route now enforces its own limit.

Impact

✅ Fewer AI request bursts
✅ Fewer video generation overages
✅ Clearer rate-limit errors

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@codeant-ai

codeant-ai Bot commented Jun 4, 2026

Copy link
Copy Markdown

CodeAnt AI is reviewing your PR.

@vercel

vercel Bot commented Jun 4, 2026

Copy link
Copy Markdown

@eshaanag is attempting to deploy a commit to the Karan Mani Tripathi 's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds enforceApiRateLimit helper and types, wires ai/general/video limiters into multiple POST routes (auth → rate-check → parse), updates middleware route matching and failure semantics, and adds tests plus a Jest mock for limiter behavior.

Changes

API Rate Limiting Infrastructure

Layer / File(s) Summary
Rate Limiting contract and helper
src/lib/api-rate-limit.ts, src/__tests__/lib/api-rate-limit.test.ts, jest.setup.ts
Adds RateLimiter, RateLimitCategory, and enforceApiRateLimit that normalizes identifiers, calls limiters, returns null on allow, emits 429 JSON + Retry-After + X-RateLimit-* when exhausted, and implements category-specific failure handling. Tests cover normalization, 429 headers/body, and fail-open/closed cases; Jest mock added for limiter instances and redisClient.

Middleware

Layer / File(s) Summary
Middleware route classification and error handling
src/middleware.tsx
Compute path once, add route-level bypasses for routes enforcing their own quotas, classify AI vs non-AI routes (include /api/doubts/check-similarity), select aiLimiter or generalLimiter, and fail closed only for AI routes on limiter errors.

AI route integration

Layer / File(s) Summary
AI imports and early guards
src/app/api/ask-ai/route.ts, src/app/api/ai-career-chat-agent/route.tsx, src/app/api/doubts/check-similarity/route.ts, src/__tests__/api/ask-ai.test.ts
Replace inline aiLimiter usage with enforceApiRateLimit(aiLimiter, identifier, 'ai') in ask-ai and ai-career-chat-agent, add early ai rate-limit guard in check-similarity (IP or authenticated email), and update ask-ai test to include type: 'standard', assert limiter call, and expect updated 429 JSON shape.

General mutation routes

Layer / File(s) Summary
General mutation endpoints
src/app/api/doubts/route.ts, src/app/api/replies/route.ts, src/app/api/doubts/[id]/bookmark/route.ts, src/app/api/rooms/route.ts, src/app/api/tags/route.ts, src/__tests__/api/doubts-similarity.test.ts
Apply enforceApiRateLimit(generalLimiter, email, "general") across mutation endpoints, reordering handlers to authenticate and rate-check before parsing/validation; tests mock enforceApiRateLimit to assert 429 short-circuits DB access.

Video route integration

Layer / File(s) Summary
Video generation and script endpoints
src/app/api/video/generate/route.ts, src/app/api/video/script/route.ts
Add enforceApiRateLimit(videoLimiter, email, 'video') early in POST handlers after email validation and return early on limit exhaustion.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

quality:clean

Suggested reviewers

  • knoxiboy
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(api): enforce route-level rate limits' directly and concisely describes the primary change: implementing route-level rate limiting across API endpoints.
Linked Issues check ✅ Passed The PR comprehensively implements all requirements from issue #506: aiLimiter applied to /api/ask-ai, /api/doubts/check-similarity, and AI career chat; generalLimiter to mutation endpoints (doubts, replies, rooms, tags, bookmarks); videoLimiter to video endpoints; normalized email keys used; 429 responses with Retry-After headers returned; fail-closed behavior for AI/video limits.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #506's requirements: adding rate-limit enforcement to specified API routes, creating the shared enforceApiRateLimit helper, updating middleware to classify routes appropriately, and adding related tests.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@github-actions github-actions Bot added gssoc'26 GSSoC program issue level:intermediate Intermediate level task labels Jun 4, 2026
@github-actions
github-actions Bot requested a review from knoxiboy June 4, 2026 08:54
@github-actions github-actions Bot added the type:bug Bug fix label Jun 4, 2026
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown

@coderabbitai review

Comment thread src/app/api/replies/route.ts Outdated
Comment thread src/app/api/video/script/route.ts
Comment thread src/app/api/doubts/check-similarity/route.ts Outdated
@codeant-ai

codeant-ai Bot commented Jun 4, 2026

Copy link
Copy Markdown

CodeAnt AI finished reviewing your PR.

@eshaanag

eshaanag commented Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the review findings in aae6886:

  • doubt, reply, and classroom creation now enforce the authenticated-email limiter before request parsing/validation, so malformed writes cannot bypass throttling
  • middleware now classifies /api/doubts/check-similarity as AI and all /api/video/* paths as video, preventing those routes from draining the general quota

Validation after the update:

  • focused rate-limit/Ask AI/reply tests pass; only the two existing doubt GET assertions fail in that focused batch
  • full Jest result remains the upstream baseline: 20/23 suites, 91/96 tests, with the same five existing failures
  • git diff --check passes

Repository owner deleted a comment from github-actions Bot Jun 4, 2026
@knoxiboy knoxiboy added ai AI prompts, models, moderation backend API routes, database, server logic labels Jun 4, 2026
@knoxiboy

knoxiboy commented Jun 4, 2026

Copy link
Copy Markdown
Owner

Hi @eshaanag! Thanks for your work on this. Before we can merge, please address the following:

  • Resolve the merge conflicts with the main branch.

Once these are fixed, the PR will be automatically evaluated again. Let us know if you need any help!

@codeant-ai

codeant-ai Bot commented Jun 4, 2026

Copy link
Copy Markdown

CodeAnt AI is running Incremental review

@codeant-ai codeant-ai Bot added the size:L label Jun 4, 2026
@github-actions github-actions Bot removed the size:L label Jun 4, 2026
@codeant-ai

codeant-ai Bot commented Jun 4, 2026

Copy link
Copy Markdown

CodeAnt AI Incremental review completed.

@eshaanag

eshaanag commented Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

Merged the latest main and resolved the conflicts in 9e551df. I kept the shared route-level limiter as the single Ask AI quota check, so the upstream limiter changes do not double-count requests, while retaining the new body/image validation tests. Build, TypeScript, ESLint, security, dependency audit, and the quality gate pass; the Unit Tests job has only the same five upstream baseline failures in doubts, room-members, and DB config (94/99 passing).

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/__tests__/lib/api-rate-limit.test.ts`:
- Around line 31-49: The test asserts exact equality for the "Retry-After"
header which flakes because Date.now() timing can shift; update the test in
src/__tests__/lib/api-rate-limit.test.ts to parse the response header from
enforceApiRateLimit (use response?.headers.get("Retry-After")) as a number
(e.g., parseInt) and assert it falls within a small acceptable range (e.g., >=29
and <=31 or >=29) instead of expecting "30" exactly; keep the rest of the
assertions (status and X-RateLimit-Limit) unchanged and reference the existing
createLimiter and enforceApiRateLimit calls to locate the assertion to modify.

In `@src/app/api/video/generate/route.ts`:
- Around line 13-14: The route is being rate-limited twice (middleware using
videoLimiter.limit(userId || ip) and this route calling
enforceApiRateLimit(videoLimiter, email, 'video'), causing inconsistent 429s;
fix by removing the duplicate quota path: either have the middleware skip
/api/video/* requests (remove or guard the call to videoLimiter.limit(userId ||
ip) in the middleware) so this route's enforceApiRateLimit(videoLimiter, email,
'video') is the single source of truth, or change the middleware to call
enforceApiRateLimit(...) itself (use enforceApiRateLimit with the email key and
standardized response shape instead of videoLimiter.limit(...) there); update
whichever you change so only one limiter invocation exists and all video
endpoints use the same key and response shape.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6c6e1d6d-5518-495e-a84d-cc22ede9ad48

📥 Commits

Reviewing files that changed from the base of the PR and between 2d98472 and 9e551df.

📒 Files selected for processing (15)
  • jest.setup.ts
  • src/__tests__/api/ask-ai.test.ts
  • src/__tests__/lib/api-rate-limit.test.ts
  • src/app/api/ai-career-chat-agent/route.tsx
  • src/app/api/ask-ai/route.ts
  • src/app/api/doubts/[id]/bookmark/route.ts
  • src/app/api/doubts/check-similarity/route.ts
  • src/app/api/doubts/route.ts
  • src/app/api/replies/route.ts
  • src/app/api/rooms/route.ts
  • src/app/api/tags/route.ts
  • src/app/api/video/generate/route.ts
  • src/app/api/video/script/route.ts
  • src/lib/api-rate-limit.ts
  • src/middleware.tsx

Comment thread src/__tests__/lib/api-rate-limit.test.ts
Comment thread src/app/api/video/generate/route.ts
@codeant-ai

codeant-ai Bot commented Jun 4, 2026

Copy link
Copy Markdown

CodeAnt AI is running Incremental review

@codeant-ai codeant-ai Bot added the size:L label Jun 4, 2026
@knoxiboy

knoxiboy commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Automated Detailed Review

Please address the above items and request a review again.

@eshaanag

eshaanag commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review. I rechecked both items:

  • The PR description already starts with Fixes #506, so the closing issue reference is present.
  • I compared the branch against the current base: this PR still adds the route-level limiter enforcement for the assigned AI/video/write paths, normalized authenticated-email keys, rate-limit headers, and focused regression coverage. I do not see the same implementation already present on base.

The repo-owned checks are passing, and the earlier approval is still present. Please re-review when convenient.

@knoxiboy knoxiboy added level:critical Critical level task and removed level:intermediate Intermediate level task labels Jun 9, 2026
@knoxiboy

Copy link
Copy Markdown
Owner

Hi! This PR currently has merge conflicts with the main branch. Please rebase/merge main and resolve conflicts so we can review and merge it. Thank you!

@knoxiboy

Copy link
Copy Markdown
Owner

Hi @eshaanag! Thanks for submitting this PR. Here is a detailed review of your changes:

🤖 Bot Review Feedback to Resolve

CodeRabbit and CodeAnt have highlighted some important issues that need to be addressed. Please prioritize fixing these:

  • File src/app/api/replies/route.ts (Line 114):
    Suggestion: The rate-limit check is executed after request parsing/validation, and the early if (errorResponse) return errorResponse; path returns before this limiter runs. That allows unlimited malformed or oversized POST attempts to bypass route-level throttling entirely. Move the limiter ch...

  • File src/app/api/video/script/route.ts (Line 20):
    Suggestion: This adds a second limiter on the script endpoint without aligning middleware routing, so a single /api/video/script request now consumes both the middleware generalLimiter bucket and this videoLimiter bucket. That can prematurely exhaust the general-write quota and trigger 429...

  • File src/app/api/doubts/check-similarity/route.ts (Line 36):
    Suggestion: This endpoint is now rate-limited as ai at the route level, but middleware still classifies /api/doubts/check-similarity as a general API path, so each call consumes both the general limiter (middleware) and AI limiter (route). That unintentionally drains the general write quota ...

  • File src/__tests__/lib/api-rate-limit.test.ts (Line 51):
    ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid exact Retry-After equality to prevent timing flakes.

Date.now() is evaluated at different instants, so "30" can intermittently become "29" in CI. Assert a small range instead.

Suggested test adjustment...
  • File src/app/api/video/generate/route.ts (Line 14):
    ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Unify video throttling with middleware or this still returns inconsistent 429s.

src/middleware.tsx already rate-limits every /api/video/* request with videoLimiter.limit(userId || ip) and its own 429 body. Adding `enforceApiRateLimit(vid...

⚙️ CI/CD Pipeline

Your PR currently has some failing checks:

  • Vercel

Note: We have recently fixed database configuration and ask-ai syntax/compilation issues on the main branch. Please pull/merge the latest main branch into your branch to get these fixes, which should resolve common test and Vercel build failures.


This is an automated review assessment. Please address the feedback above to move your PR forward.

@knoxiboy

Copy link
Copy Markdown
Owner

⚠️ Merge Conflicts Detected

Hi @eshaanag, your branch has merge conflicts with the base branch. Please resolve them by running the following commands in your terminal:

git checkout fix/api-route-rate-limits
git pull origin main
# Resolve the conflicts in your files, then stage them
git add .
git commit -m "chore: resolve merge conflicts with main"
git push origin fix/api-route-rate-limits

If you do not have write permissions to push directly, please push to your fork branch instead.

@knoxiboy knoxiboy added level:advanced Advanced level task and removed level:critical Critical level task labels Jun 22, 2026
@github-actions github-actions Bot added the merge-conflict PR has merge conflicts that need resolution label Jun 22, 2026
@codeant-ai

codeant-ai Bot commented Jun 25, 2026

Copy link
Copy Markdown

CodeAnt AI is running Incremental review

@codeant-ai

codeant-ai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai codeant-ai Bot added the size:L label Jun 25, 2026
@github-actions github-actions Bot removed the size:L label Jun 25, 2026
@codeant-ai

codeant-ai Bot commented Jun 25, 2026

Copy link
Copy Markdown

CodeAnt AI Incremental review completed.

@eshaanag
eshaanag force-pushed the fix/api-route-rate-limits branch from bab1031 to 7ca8fc7 Compare June 25, 2026 06:49
@eshaanag
eshaanag force-pushed the fix/api-route-rate-limits branch from 7ca8fc7 to 8b7d60d Compare June 25, 2026 07:05
@github-actions github-actions Bot added size/xl and removed size/l merge-conflict PR has merge conflicts that need resolution labels Jun 25, 2026
@knoxiboy
knoxiboy merged commit 37cac93 into knoxiboy:main Jun 27, 2026
11 of 13 checks passed
@github-actions github-actions Bot added gssoc:approved Approved for GSSoC quality:clean Clean code quality and removed size/xl review-needed labels Jun 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai AI prompts, models, moderation backend API routes, database, server logic gssoc:approved Approved for GSSoC gssoc'26 GSSoC program issue level:advanced Advanced level task quality:clean Clean code quality type:bug Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Apply rate limiting to all AI and write-heavy API routes

2 participants