Skip to content

Commit ae0b2f6

Browse files
committed
Update docs for nestjs-api-gateway: feat: add mcp server
1 parent 45e68ce commit ae0b2f6

1 file changed

Lines changed: 48 additions & 3 deletions

File tree

pages/nestjs-api-gateway/index.md

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,11 @@ Import the `ApiGatewayModule` and use the `forRoot` method to configure the API
5353
showExtensions: false,
5454
},
5555
throttler: {
56-
globalRateLimit: 60,
57-
isEnable: true,
58-
globalRateLimitTTL: 60
56+
globalIpRateLimit: 120,
57+
globalIpRateLimitTTL: 60,
58+
globalCustomRateLimit: 60,
59+
globalCustomRateLimitTTL: 60,
60+
isEnable: true
5961
}
6062
})
6163
],
@@ -133,6 +135,49 @@ index(): string {
133135
}
134136
```
135137

138+
#### Global rate limits
139+
The throttler enforces two independent global limits on every request:
140+
141+
- **`globalIpRateLimit` / `globalIpRateLimitTTL`** — always bucketed by `request.ip`. This is a DDoS / abuse baseline that does **not** go through `keyResolver` and is **not** skipped when the resolver returns an empty value.
142+
- **`globalCustomRateLimit` / `globalCustomRateLimitTTL`** — bucketed by whatever `keyResolver` returns (or `request.ip` if no resolver is configured). Skipped entirely when the resolver returns an empty value.
143+
144+
A request is rejected as soon as either limit is exceeded.
145+
146+
#### Custom rate-limit key
147+
By default the custom limit buckets requests by `request.ip`. To bucket by something else (authenticated user id, tenant id, API key, etc.), supply a `keyResolver` callback in the throttler options. The callback receives `{ request, routerDetail }` and returns the string to use as the bucket identity.
148+
149+
```typescript
150+
ApiGatewayModule.forRoot({
151+
// ... other options ...
152+
throttler: {
153+
globalIpRateLimit: 120,
154+
globalIpRateLimitTTL: 60,
155+
globalCustomRateLimit: 60,
156+
globalCustomRateLimitTTL: 60,
157+
isEnable: true,
158+
keyResolver: ({ request }) => {
159+
const userId = request.headers['auth-user-id'];
160+
return typeof userId === 'string' && userId.length > 0
161+
? `user:${userId}`
162+
: `ip:${request.ip}`;
163+
}
164+
}
165+
})
166+
```
167+
168+
**Skip the custom limit for selected requests** by returning an empty value (`null`, `undefined`, `''`, or a whitespace-only string). The throttler then bypasses both the custom global limit and any per-endpoint `@ApiRateLimit` rules without incrementing their counters. The IP-based global limit still applies.
169+
170+
```typescript
171+
keyResolver: ({ request, routerDetail }) => {
172+
if (request.url === '/healthz') return null; // skip health checks
173+
if (routerDetail.operationId === 'InternalProbeController_ping') return null; // skip by operation id
174+
const userId = request.headers['auth-user-id'];
175+
return typeof userId === 'string' && userId.length > 0 ? `user:${userId}` : `ip:${request.ip}`;
176+
}
177+
```
178+
179+
The same identity is used for the custom global limit and for any per-endpoint `@ApiRateLimit` rule. Resolvers may be asynchronous. If the resolver throws, the error propagates through the gateway's existing exception pipeline (no silent allow, no silent deny). If `keyResolver` is omitted, the custom limit falls back to `request.ip` (matching the IP limit's bucketing key). See `specs/002-throttler-key-callback/quickstart.md` for the full walkthrough.
180+
136181
## Support:
137182

138183
If you encounter any issues, have questions, or need assistance with the API Gateway, please contact the development team

0 commit comments

Comments
 (0)