Rate Limiting
Nexar includes built-in rate limiting to ensure your application complies with Riot's API rate limits and avoids getting rate limited.
Note
If the rate limit is met, and a Retry-After is provided by Riot, Nexar will simply wait the small duration and continue.
Default Rate Limits
By default, Nexar enforces the following rate limits:
- 20 requests per 1 second
- 100 requests per 2 minutes
These are the standard Riot API limits for most personal applications.
Basic Usage
Rate limiting is enabled automatically when you create a NexarClient:
# Rate limiting is automatically applied to all API calls
account = await client.get_riot_account("bexli", "bex")
Custom Rate Limits
You can configure custom rate limits if needed:
client_custom_limits = NexarClient(
riot_api_key=api_key,
default_region=Region.NA1,
per_second_limit=(1, 1), # Max of 1 request per second
per_minute_limit=(10, 5), # Max of 10 requests per 5 minutes
)
async with client_custom_limits:
# Use client here
pass
Persistent Rate Limiting
Nexar uses SQLite to track rate limits by default. This ensures that your application remains compliant with Riot's API limits even if you restart your script or application.
rate_limits.db
Unlike memory-only rate limiters, Nexar's RateLimitStorage persists token counts to a local database file (default: ~/.nexar/rate_limits.db). This prevents "limit resetting" on restart, which can lead to 429 errors.
You can customize the database path:
import asyncio
import os
from nexar.client import NexarClient
from nexar.enums import Region
# 1. Provide your API key (or set NEXAR_RIOT_API_KEY env var)
RIOT_API_KEY = os.environ.get("NEXAR_RIOT_API_KEY", "RGAPI-YOUR-KEY-HERE")
async def main():
# 2. Configure the client with a custom database path
# This ensures that rate limit tokens persist even if the script restarts.
# Default path is "rate_limits.db" in the current directory.
async with NexarClient(
riot_api_key=RIOT_API_KEY, default_region=Region.NA1, rate_limit_db_path="my_custom_limits.db"
) as client:
print(f"Using rate limit database at: {client.rate_limit_storage.db_path}")
try:
# 3. Make an API call to trigger the rate limiter
account = await client.get_riot_account("Dyrus", "NA1")
print(f"Success! Found account: {account.game_name}#{account.tag_line}")
# 4. Check the database file exists
if os.path.exists("my_custom_limits.db"):
print("Confirmed: 'my_custom_limits.db' was created.")
else:
print("Warning: Database file not found (it might be created lazily).")
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
asyncio.run(main())
How It Works
Nexar automatically enforces Riot's API rate limits by sleeping between calls. It uses aiosqlite to store token usage in a local file, ensuring state is preserved across runs.
Cached responses do not count against rate limits.
Logging
The rate limiter provides detailed logging to help you understand its behavior. You can configure logging levels using configure_logging.
Example Log Output
[nexar] Rate limiter initialized with 2 limits:
[nexar] Limit 1: 20 requests per 1s
[nexar] Limit 2: 100 requests per 120s
[nexar] Limit 1: 19/20 used, 1 remaining
[nexar] Limit 2: 45/100 used, 55 remaining
[nexar] Rate limit hit! Limit 1 (20 req/1s) - waiting 0.85 seconds
[nexar] Rate limit wait complete - proceeding with request
Rate Limiting vs Caching
Rate limiting and caching work together intelligently:
- Cached responses don't count against rate limits since no actual API request is made
- Fresh requests are subject to rate limiting to ensure compliance with Riot's limits
- Cache hits are instant and don't consume any rate limit quota
- Cache misses trigger rate limiting before making the actual API call
This means you can make the same API call repeatedly without worrying about rate limits if the response is cached. Only unique requests or expired cache entries will consume your rate limit quota.
Example
# First call - fresh request, counts against rate limits
account = await client.get_riot_account("bexli", "bex") # Rate limited if needed
# Subsequent calls - cached, no rate limiting
account = await client.get_riot_account("bexli", "bex") # Instant, no rate limit check
account = await client.get_riot_account("bexli", "bex") # Instant, no rate limit check
# Different account - fresh request, rate limited
other = await client.get_riot_account("Doublelift", "NA1") # Rate limited if needed