Install: pip install kinglet or add dependencies = ["kinglet"] to pyproject.toml
import os
from kinglet import Kinglet, CorsMiddleware, Response, cache_aside_d1
app = Kinglet(root_path="/api")
# Flexible middleware (v1.4.2+)
app.add_middleware(CorsMiddleware(allow_origin="*"))
# Routes are default-deny (2.0): each is public=True or carries an auth decorator
@app.post("/auth/login", public=True)
async def login(request):
data = await request.json()
return {"token": "jwt-token", "user": data["email"]}
@app.get("/api/data", public=True)
@cache_aside_d1(cache_type="api_data", ttl=1800) # D1 caching (v1.5.0+)
async def get_data(request):
return {"data": "cached_in_prod_fresh_in_dev"}On app.asgi, request bodies are read only when accessed and are limited to 1 MiB by default. Set Kinglet(max_body_size=8 * 1024 * 1024) for larger uploads. The limit counts actual received bytes, including requests without Content-Length; exceeding it returns HTTP 413. Authentication that only needs headers runs before body reads.
| Feature | Kinglet | FastAPI | Flask |
|---|---|---|---|
| Bundle Size | 272KB | 7.8MB | 1.9MB |
| Testing | No server needed | TestServer required | Test client required |
| Workers Ready | ✅ Built-in | ❌ Complex setup | ❌ Not compatible |
Core: Decorator routing, typed parameters, flexible middleware, auto error handling, serverless testing Cloudflare: D1/R2/KV helpers, D1-backed caching, environment-aware policies, CDN-aware URLs Database: Micro-ORM for D1 with migrations, field validation, bulk operations (v1.6.0+) Security: Default-deny routes, JWT validation, TOTP/2FA, fine-grained auth/ownership decorators Developer: Full type hints, debug mode, request validation, zero-dependency testing OpenAPI: Auto-generated Swagger/ReDoc docs from routes and models (v1.8.0+)
Typed Parameters & Auth:
from kinglet.authz import require_auth # or wrap your own with @security_decorator
@app.get("/users/{user_id}")
@require_auth # JWT auth; route decorator stays outermost
async def get_user(request):
user_id = request.path_param_int("user_id") # Validates or returns 400
limit = request.query_int("limit", 10) # Query params with defaults
return {"user": user_id, "limit": limit}Flexible Middleware & Caching:
# Configure middleware with parameters
cors = CorsMiddleware(allow_origin="*", allow_methods="GET,POST")
app.add_middleware(cors)
# D1-backed caching (v1.5.0+) - faster and cheaper for <1MB responses
@app.get("/api/data", public=True)
@cache_aside_d1(cache_type="api_data", ttl=1800) # D1 primary, R2 fallback
async def get_data(request):
return {"data": "expensive_query_result"}
# R2-backed caching for larger responses
@app.get("/api/large", public=True)
@cache_aside(cache_type="large_data", ttl=3600) # Environment-aware
async def get_large_data(request):
return {"data": "large_expensive_query_result"}D1 Micro-ORM (v1.6.0+):
from kinglet import Model, StringField, IntegerField
class Game(Model):
title = StringField(max_length=200)
score = IntegerField(default=0)
# Simple CRUD with field validation
game = await Game.objects.create(db, title="Pac-Man", score=100)
top_games = await Game.objects.filter(db, score__gte=90).order_by("-score").all()Use explicit keywords for boolean-shaped IntegerField arguments:
IntegerField(default=True) and IntegerField(index=True). Positional booleans
such as IntegerField(True) are rejected as ambiguous.
Security & Access Control:
@app.get("/admin/debug")
@require_dev() # 404 in production (blackhole) - satisfies the route policy
@geo_restrict(allowed=["US"]) # 451 elsewhere - a filter, not auth (needs public/auth too)
async def debug_endpoint(request):
return {"debug": "sensitive data"}Testing (No Server):
def test_api():
client = TestClient(app)
status, headers, body = client.request("GET", "/users/123")
assert status == 200OpenAPI/Swagger Documentation (v1.8.0+):
from kinglet import SchemaGenerator, Response
@app.get("/openapi.json", public=True)
async def openapi_spec(request):
generator = SchemaGenerator(app, title="My API", version="1.0.0")
return Response(generator.generate_spec())
@app.get("/docs", public=True)
async def swagger_ui(request):
generator = SchemaGenerator(app, title="My API")
return Response(generator.serve_swagger_ui(), content_type="text/html")
# Auto-generates docs from validators and models
# Visit /docs for interactive Swagger UI- Examples - Quick start examples for all features
- ORM Guide - D1 micro-ORM with migrations
- Caching Guide - Environment-aware caching
- Middleware Guide - Flexible middleware system
- Security Guide - Security patterns, TOTP/2FA
Built for Cloudflare Workers Python community. Need help?
