add-rate-limiting
Configure rate limiting policies for API endpoints with sliding window limits
Best use case
add-rate-limiting is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Configure rate limiting policies for API endpoints with sliding window limits
Teams using add-rate-limiting should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/add-rate-limiting/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How add-rate-limiting Compares
| Feature / Agent | add-rate-limiting | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Configure rate limiting policies for API endpoints with sliding window limits
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Add Rate Limiting Skill
Configure rate limiting for NovaTune API endpoints.
## Project Context
- Configuration: `src/NovaTuneApp/NovaTuneApp.ApiService/appsettings.json`
- Rate limit setup: `src/NovaTuneApp/NovaTuneApp.ApiService/Program.cs`
- Policies: `src/NovaTuneApp/NovaTuneApp.ApiService/Infrastructure/RateLimiting/`
## Steps
### 1. Add Configuration Section
Location: `appsettings.json`
```json
{
"RateLimiting": {
"Auth": {
"LoginPerIp": { "PermitLimit": 10, "WindowMinutes": 1 },
"LoginPerAccount": { "PermitLimit": 5, "WindowMinutes": 1 },
"RegisterPerIp": { "PermitLimit": 10, "WindowMinutes": 1 },
"RefreshPerIp": { "PermitLimit": 20, "WindowMinutes": 1 }
},
"Upload": {
"PerUser": { "PermitLimit": 20, "WindowMinutes": 60 },
"BurstPerUser": { "PermitLimit": 5, "WindowMinutes": 1 }
},
"Streaming": {
"PerUser": { "PermitLimit": 60, "WindowMinutes": 1 },
"PerTrack": { "PermitLimit": 10, "WindowMinutes": 1 }
},
"Telemetry": {
"PerDevice": { "PermitLimit": 120, "WindowMinutes": 1 }
}
}
}
```
### 2. Create Rate Limit Settings Classes
Location: `src/NovaTuneApp/NovaTuneApp.ApiService/Configuration/RateLimitSettings.cs`
```csharp
public class RateLimitSettings
{
public const string SectionName = "RateLimiting";
public AuthRateLimits Auth { get; set; } = new();
public UploadRateLimits Upload { get; set; } = new();
public StreamingRateLimits Streaming { get; set; } = new();
public TelemetryRateLimits Telemetry { get; set; } = new();
}
public class AuthRateLimits
{
public RateLimitPolicy LoginPerIp { get; set; } = new(10, 1);
public RateLimitPolicy LoginPerAccount { get; set; } = new(5, 1);
public RateLimitPolicy RegisterPerIp { get; set; } = new(10, 1);
public RateLimitPolicy RefreshPerIp { get; set; } = new(20, 1);
}
public class UploadRateLimits
{
public RateLimitPolicy PerUser { get; set; } = new(20, 60);
public RateLimitPolicy BurstPerUser { get; set; } = new(5, 1);
}
public class StreamingRateLimits
{
public RateLimitPolicy PerUser { get; set; } = new(60, 1);
public RateLimitPolicy PerTrack { get; set; } = new(10, 1);
}
public class TelemetryRateLimits
{
public RateLimitPolicy PerDevice { get; set; } = new(120, 1);
}
public record RateLimitPolicy(int PermitLimit, int WindowMinutes);
```
### 3. Configure Rate Limiting in Program.cs
```csharp
using System.Threading.RateLimiting;
var rateLimitSettings = builder.Configuration
.GetSection(RateLimitSettings.SectionName)
.Get<RateLimitSettings>() ?? new();
builder.Services.AddRateLimiter(options =>
{
options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
// Global policy for unmatched endpoints
options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(context =>
RateLimitPartition.GetSlidingWindowLimiter(
partitionKey: context.Connection.RemoteIpAddress?.ToString() ?? "unknown",
factory: _ => new SlidingWindowRateLimiterOptions
{
PermitLimit = 100,
Window = TimeSpan.FromMinutes(1),
SegmentsPerWindow = 4
}));
// Auth: Login per IP
options.AddPolicy("auth-login-ip", context =>
RateLimitPartition.GetSlidingWindowLimiter(
partitionKey: context.Connection.RemoteIpAddress?.ToString() ?? "unknown",
factory: _ => new SlidingWindowRateLimiterOptions
{
PermitLimit = rateLimitSettings.Auth.LoginPerIp.PermitLimit,
Window = TimeSpan.FromMinutes(rateLimitSettings.Auth.LoginPerIp.WindowMinutes),
SegmentsPerWindow = 4
}));
// Auth: Login per account (extracted from request body - needs custom logic)
options.AddPolicy("auth-login-account", context =>
RateLimitPartition.GetSlidingWindowLimiter(
partitionKey: GetAccountKeyFromRequest(context),
factory: _ => new SlidingWindowRateLimiterOptions
{
PermitLimit = rateLimitSettings.Auth.LoginPerAccount.PermitLimit,
Window = TimeSpan.FromMinutes(rateLimitSettings.Auth.LoginPerAccount.WindowMinutes),
SegmentsPerWindow = 4
}));
// Auth: Register per IP
options.AddPolicy("auth-register", context =>
RateLimitPartition.GetSlidingWindowLimiter(
partitionKey: context.Connection.RemoteIpAddress?.ToString() ?? "unknown",
factory: _ => new SlidingWindowRateLimiterOptions
{
PermitLimit = rateLimitSettings.Auth.RegisterPerIp.PermitLimit,
Window = TimeSpan.FromMinutes(rateLimitSettings.Auth.RegisterPerIp.WindowMinutes),
SegmentsPerWindow = 4
}));
// Upload per user
options.AddPolicy("upload-user", context =>
RateLimitPartition.GetSlidingWindowLimiter(
partitionKey: context.User.FindFirstValue(ClaimTypes.NameIdentifier) ?? "anonymous",
factory: _ => new SlidingWindowRateLimiterOptions
{
PermitLimit = rateLimitSettings.Upload.PerUser.PermitLimit,
Window = TimeSpan.FromMinutes(rateLimitSettings.Upload.PerUser.WindowMinutes),
SegmentsPerWindow = 6
}));
// Streaming per user
options.AddPolicy("streaming-user", context =>
RateLimitPartition.GetSlidingWindowLimiter(
partitionKey: context.User.FindFirstValue(ClaimTypes.NameIdentifier) ?? "anonymous",
factory: _ => new SlidingWindowRateLimiterOptions
{
PermitLimit = rateLimitSettings.Streaming.PerUser.PermitLimit,
Window = TimeSpan.FromMinutes(rateLimitSettings.Streaming.PerUser.WindowMinutes),
SegmentsPerWindow = 4
}));
// On rejected: add Retry-After header
options.OnRejected = async (context, token) =>
{
context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;
if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter))
{
context.HttpContext.Response.Headers.RetryAfter =
((int)retryAfter.TotalSeconds).ToString();
}
// Return Problem Details
await context.HttpContext.Response.WriteAsJsonAsync(new ProblemDetails
{
Type = "https://novatune.example/errors/rate-limit-exceeded",
Title = "Rate Limit Exceeded",
Status = StatusCodes.Status429TooManyRequests,
Detail = "Too many requests. Please try again later."
}, token);
// Log the violation
var logger = context.HttpContext.RequestServices
.GetRequiredService<ILogger<Program>>();
logger.LogWarning(
"Rate limit exceeded for {Endpoint} from {IP}",
context.HttpContext.Request.Path,
context.HttpContext.Connection.RemoteIpAddress);
};
});
// Helper to extract email from login request
static string GetAccountKeyFromRequest(HttpContext context)
{
// For login endpoint, extract email from request
// This requires request body buffering
if (context.Items.TryGetValue("login-email", out var email) && email is string emailStr)
return emailStr.ToLowerInvariant();
return context.Connection.RemoteIpAddress?.ToString() ?? "unknown";
}
```
### 4. Apply Rate Limiting Middleware
```csharp
// After app.Build()
app.UseRateLimiter();
// Apply to auth endpoints
app.MapPost("/auth/login", Login)
.RequireRateLimiting("auth-login-ip");
app.MapPost("/auth/register", Register)
.RequireRateLimiting("auth-register");
// Apply to upload endpoints
app.MapPost("/tracks/upload/initiate", InitiateUpload)
.RequireRateLimiting("upload-user");
// Apply to streaming endpoints
app.MapPost("/tracks/{id}/stream", GetStreamUrl)
.RequireRateLimiting("streaming-user");
```
### 5. Create Middleware for Account-Based Rate Limiting
For login endpoint, extract email before rate limiting:
```csharp
public class LoginRateLimitMiddleware
{
private readonly RequestDelegate _next;
public LoginRateLimitMiddleware(RequestDelegate next) => _next = next;
public async Task InvokeAsync(HttpContext context)
{
if (context.Request.Path.StartsWithSegments("/auth/login") &&
context.Request.Method == "POST")
{
context.Request.EnableBuffering();
using var reader = new StreamReader(context.Request.Body, leaveOpen: true);
var body = await reader.ReadToEndAsync();
context.Request.Body.Position = 0;
try
{
var login = JsonSerializer.Deserialize<LoginRequest>(body);
if (login?.Email != null)
{
context.Items["login-email"] = login.Email;
}
}
catch { /* Ignore parse errors */ }
}
await _next(context);
}
}
// Register before rate limiter
app.UseMiddleware<LoginRateLimitMiddleware>();
app.UseRateLimiter();
```
## Default Rate Limits (NF-2.5)
| Endpoint | Per IP | Per Account/User | Window |
|----------|--------|------------------|--------|
| `/auth/login` | 10 | 5 | 1 min |
| `/auth/register` | 10 | N/A | 1 min |
| `/auth/refresh` | 20 | N/A | 1 min |
| `/tracks/upload/initiate` | N/A | 20 (burst: 5/min) | 1 hour |
| `/tracks/{id}/stream` | N/A | 60 | 1 min |
| `/telemetry/*` | N/A | 120/device | 1 min |
## Response Format
When rate limited, return HTTP 429 with:
```http
HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/problem+json
{
"type": "https://novatune.example/errors/rate-limit-exceeded",
"title": "Rate Limit Exceeded",
"status": 429,
"detail": "Too many requests. Please try again later."
}
```
## Testing
```csharp
[Fact]
public async Task Login_Returns429_WhenRateLimitExceeded()
{
// Make 11 requests (limit is 10)
for (int i = 0; i < 11; i++)
{
var response = await _client.PostAsJsonAsync("/auth/login", new
{
Email = "test@example.com",
Password = "wrong"
});
if (i < 10)
{
response.StatusCode.Should().NotBe(HttpStatusCode.TooManyRequests);
}
else
{
response.StatusCode.Should().Be(HttpStatusCode.TooManyRequests);
response.Headers.Should().ContainKey("Retry-After");
}
}
}
```
## Observability
Log rate limit violations for monitoring:
```csharp
logger.LogWarning(
"Rate limit exceeded: Endpoint={Endpoint}, IP={IP}, Policy={Policy}",
context.Request.Path,
context.Connection.RemoteIpAddress,
policyName);
```
Add metrics:
```csharp
_meter.CreateCounter<long>("rate_limit_exceeded_total")
.Add(1, new KeyValuePair<string, object?>("endpoint", endpoint));
```Related Skills
advanced-memoization-strategies
Apply principled memoization techniques to reduce re-rendering without introducing correctness bugs.
advanced-caching-strategies
Multi-layer caching strategies across CDN, browser, server, and database. PROACTIVELY activate for: (1) HTTP caching headers, (2) CDN configuration, (3) Server-side caching with Redis, (4) Cache invalidation strategies, (5) ETag implementation. Triggers: "caching", "cache strategy", "CDN", "browser cache", "server cache", "redis", "cache invalidation", "ETag", "Cache-Control"
Adaptive Bitrate Streaming
Automatically adjusting video quality based on network conditions using HLS, DASH protocols and player implementation for smooth playback and optimal user experience.
huggingface-accelerate
Simplest distributed training API. 4 lines to add distributed support to any PyTorch script. Unified API for DeepSpeed/FSDP/Megatron/DDP. Automatic device placement, mixed precision (FP16/BF16/FP8). Interactive config, single launch command. HuggingFace ecosystem standard.
acc-create-strategy
Generates Strategy pattern for PHP 8.5. Creates interchangeable algorithm families with context class, strategy interface, and concrete implementations. Includes unit tests.
acc-create-rate-limiter
Generates Rate Limiter pattern for PHP 8.5. Creates request throttling with token bucket, sliding window, and fixed window algorithms. Includes unit tests.
abstract-strategy
Design abstract strategy games with perfect information, no randomness, and strategic depth. Use when designing a board game, exploring abstract strategy games, brainstorming game mechanics, or evaluating game balance. Keywords: board game, game design, strategy, mechanics, balance.
grail-miner
This skill assists in setting up, managing, and optimizing Grail miners on Bittensor Subnet 81, handling tasks like environment configuration, R2 storage, model checkpoint management, and performance tuning.
lets-go-rss
A lightweight, full-platform RSS subscription manager that aggregates content from YouTube, Vimeo, Behance, Twitter/X, and Chinese platforms like Bilibili, Weibo, and Douyin, featuring deduplication and AI smart classification.
ontopo
An AI agent skill to search for Israeli restaurants, check table availability, view menus, and retrieve booking links via the Ontopo platform, acting as an unofficial interface to its data.
whisper-transcribe
Transcribes audio and video files to text using OpenAI's Whisper CLI, enhanced with contextual grounding from local markdown files for improved accuracy.
thor-skills
An entry point and router for AI agents to manage various THOR-related cybersecurity tasks, including running scans, analyzing logs, troubleshooting, and maintenance.