Skip to Content
FrontendSecurityRate limiting implementation

Rate limiting implementation

This is how rate limiting is applied to API routes in the apps.

Overview

Rate limiting is implemented in two ways:

  1. Per-route wrapper – Internal API route handlers are wrapped with withApiRateLimit from @phpcreation/frontend-utils-react-nextjs-bundle/utils/backend-helpers. Each route has its own limit key so limits are tracked separately per endpoint.
  2. callOut – The external API route /api/callOut uses getHandler, postHandler, and patchHandler from 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 with withApiRateLimit.

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)

RouteMethodkeyPrefix
/api/logoutPOSTapi-logout
/api/config-loginPOSTapi-config-login
/api/oauth/authorizeGETapi-oauth-authorize
/api/oauth/callbackGETapi-oauth-callback
/api/statusGETapi-status
/api/status/allGETapi-status-all
/api/status/apiGETapi-status-api
/api/status/cacheGETapi-status-cache
/api/status/configsGETapi-status-configs
/api/status/user-token/checkGETapi-status-user-token-check
/api/status/user-token/displayGETapi-status-user-token-display
/api/status/user-token/expectedGETapi-status-user-token-expected
/api/clear-cacheDELETEapi-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.ts uses getHandler, postHandler, and patchHandler from 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 the API_RATE_LIMIT environment 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.
Last updated on