Rate limiting implementation
This is how rate limiting is applied to API routes in the apps.
Overview
Rate limiting is implemented in two ways:
- Per-route wrapper – Internal API route handlers are wrapped with
withApiRateLimitfrom@phpcreation/frontend-utils-react-nextjs-bundle/utils/backend-helpers. Each route has its own limit key so limits are tracked separately per endpoint. - callOut – The external API route
/api/callOutusesgetHandler,postHandler, andpatchHandlerfrom the same bundle, with a configurable max-requests value (e.g. per 10s window). callOut uses the same rate limiting mechanism as the internal API routes so no need to wrap it withwithApiRateLimit.
The actual limit values, time windows, and storage are defined inside https://github.com/PHPCreation/frontend-utils-react-nextjs-bundle/blob/main/src/utils/backend-helpers/RateLimiter.ts.
Internal API routes: withApiRateLimit
Usage
Each route exports the handler wrapped with withApiRateLimit(handler, options):
import { withApiRateLimit } from "@phpcreation/frontend-utils-react-nextjs-bundle/utils/backend-helpers";
async function myHandler(request: NextRequest) {
// ...
}
export const GET = withApiRateLimit(myHandler, { keyPrefix: "my-route" });The keyPrefix option identifies the route in the rate limiter (e.g. for namespacing or per-endpoint limits). Different prefixes mean limits are tracked separately for each route.
Routes that use it
These are the general routes used in most projects. (of course each project may have its own routes and keys)
| Route | Method | keyPrefix |
|---|---|---|
/api/logout | POST | api-logout |
/api/config-login | POST | api-config-login |
/api/oauth/authorize | GET | api-oauth-authorize |
/api/oauth/callback | GET | api-oauth-callback |
/api/status | GET | api-status |
/api/status/all | GET | api-status-all |
/api/status/api | GET | api-status-api |
/api/status/cache | GET | api-status-cache |
/api/status/configs | GET | api-status-configs |
/api/status/user-token/check | GET | api-status-user-token-check |
/api/status/user-token/display | GET | api-status-user-token-display |
/api/status/user-token/expected | GET | api-status-user-token-expected |
/api/clear-cache | DELETE | api-clear-cache |
When a client exceeds the limit for a given key, the bundle typically returns 429 Too Many Requests.
2. External API (callOut) /api/callOut
In general, most external API calls that go through CallAPI() are sent via /api/callOut.
- Implementation:
src/app/api/callOut/route.tsusesgetHandler,postHandler, andpatchHandlerfrom the same backend-helpers, passing an axios instance and a max requests value. - Configurable limit:
API_RATE_LIMIT = Number(process.env.API_RATE_LIMIT) || 50
So the limit is 50 requests per window (default) unless overridden by theAPI_RATE_LIMITenvironment variable. The time window is 10 sec.
/** Rate limit: max requests per 10s window (utils bundle default). */
const API_RATE_LIMIT = Number(process.env.API_RATE_LIMIT) || 50;
export async function GET(request: NextRequest) {
return await getHandler(request, axiosInstance, API_RATE_LIMIT);
}
// POST and PATCH similarly.