api-rate-limiting
Implements per-client API rate limiting in a Lauren application using a token-bucket algorithm and a guard. Use when protecting endpoints from abuse, enforcing quotas, or adding fair-use policies.
Works with
---
name: api-rate-limiting
description: Implements per-client API rate limiting in a Lauren application using a token-bucket algorithm and a guard. Use when protecting endpoints from abuse, enforcing quotas, or adding fair-use policies.
license: MIT
---
> Use `codemap find "use_guards"` to locate existing guard registrations before adding a new limiter.
# API Rate Limiting (Token Bucket)
The pattern uses two injectable singletons:
1. **`TokenBucketLimiter`** — stateful bucket store; one bucket per client key (e.g., IP address).
2. **`RateLimitGuard`** — a guard that calls `consume()` and raises HTTP 429 on exhaustion.
## Token bucket implementation
```python
from __future__ import annotations
import time
from lauren import injectable, Scope
@injectable(scope=Scope.SINGLETON)
class TokenBucketLimiter:
"""Token-bucket rate limiter — thread-safe for single-process deployments."""
def __init__(self, capacity: int = 60, refill_rate: float = 1.0) -> None:
self._capacity = capacity
self._refill_rate = refill_rate # tokens per second
self._buckets: dict[str, dict] = {}
def _get_bucket(self, key: str) -> dict:
if key not in self._buckets:
self._buckets[key] = {
"tokens": float(self._capacity),
"last_refill": time.monotonic(),
}
return self._buckets[key]
def consume(self, key: str, tokens: int = 1) -> bool:
bucket = self._get_bucket(key)
now = time.monotonic()
elapsed = now - bucket["last_refill"]
bucket["tokens"] = min(
float(self._capacity),
bucket["tokens"] + elapsed * self._refill_rate,
)
bucket["last_refill"] = now
if bucket["tokens"] >= tokens:
bucket["tokens"] -= tokens
return True
return False
```
## Rate limit guard
```python
from lauren import injectable, Scope
from lauren.types import ExecutionContext
from lauren.exceptions import HTTPError
class RateLimitError(HTTPError):
status_code = 429
code = "rate_limit_exceeded"
@injectable(scope=Scope.SINGLETON)
class RateLimitGuard:
def __init__(self, limiter: TokenBucketLimiter) -> None:
self._limiter = limiter
async def can_activate(self, ctx: ExecutionContext) -> bool:
client_ip = ctx.request.headers.get("x-forwarded-for", "127.0.0.1")
if not self._limiter.consume(client_ip):
raise RateLimitError("Rate limit exceeded")
return True
```
## Controller with guard
```python
from lauren import controller, get, module, use_guards
@use_guards(RateLimitGuard)
@controller("/api")
class RateLimitedController:
@get("/data")
async def data(self) -> dict:
return {"data": "ok"}
@module(
controllers=[RateLimitedController],
providers=[RateLimitGuard, TokenBucketLimiter],
)
class RateLimitModule:
pass
```
## Customising capacity per route
Apply `@use_guards` at the method level to use a different guard instance, or use `set_metadata` to pass the limit:
```python
from lauren import set_metadata, use_guards
@controller("/api")
class MyController:
@get("/cheap")
@use_guards(RateLimitGuard)
async def cheap(self) -> dict:
return {"ok": True}
@get("/expensive")
@use_guards(RateLimitGuard)
@set_metadata("rate_limit_cost", 5)
async def expensive(self) -> dict:
return {"ok": True}
```
Then read `ctx.get_metadata("rate_limit_cost", 1)` inside `can_activate`.
## Key points
- `TokenBucketLimiter` is a singleton so its state persists across requests within a process. For multi-worker setups, back the bucket store with Redis.
- `RateLimitError` subclasses `HTTPError` with `status_code = 429` — the ASGI adapter converts it to a JSON 429 response automatically.
- Use `x-forwarded-for` for IP extraction when behind a reverse proxy; validate trust level in production.
- Applying `@use_guards` on the controller class applies the guard to all routes on that controller.More API Design skills
lark-event
larksuite/cli
Lark/Feishu real-time event listening / subscribing / consuming: stream events as NDJSON via `lark-cli event consume <EventKey>` (covers IM messages/reactions/chat changes, Approval status changes, Task updates, VC meeting started/joined/ended, Minutes generated, Whiteboard updated, etc.). Use for Lark bots, real-time message processing, long-running subscribers, streaming webhook/push handlers. Supports `--max-events` / `--timeout` bounded runs and a stderr ready-marker contract — designed for AI agents running as subprocesses.
lark-contact
larksuite/cli
飞书 / Lark 通讯录:按姓名 / 邮箱解析成 open_id,或按 open_id 反查姓名 / 部门 / 邮箱 / 联系方式 / 个人状态 / 签名,以及按关键词搜索当前用户可见的机器人 / 智能体(agent)。当用户提到一个名字要下一步发消息 / 排日程,或拿到 open_id 想查具体信息时使用。不负责部门树遍历、按部门列员工、组织架构图,这类需求走原生 OpenAPI。
lark-openapi-explorer
larksuite/cli
飞书/Lark 原生 OpenAPI 探索:从官方文档库中挖掘未经 CLI 封装的原生 OpenAPI 接口。当用户的需求无法被现有 lark-* skill 或 lark-cli 已注册命令满足,需要查找并调用原生飞书 OpenAPI 时使用。

