A simple and fast ASGI microframework for Python with WebSocket support.
Project description
AltAPI
A simple and fast ASGI microframework for Python with WebSocket support.
Changelog
v1.4.0
- Added Dependency Injection system with automatic cleanup:
- Generator-based dependencies with
yieldfor resource management - Nested dependencies (dependencies can depend on other dependencies)
- Per-request caching of dependencies
- Async dependency support
- Automatic
Requestinjection into dependencies
- Generator-based dependencies with
- Added Request State (
request.state) for passing data between middleware and handlers - Rate Limiting optimized — migrated to Shared Memory architecture:
- Zero network overhead for multi-worker synchronization
- Fixed race conditions in request counting
- Memory leak fixes in storage backends
- Added examples:
- 'examples/webapp.py' - full user managment system
- Fixed cleanup guarantees —
finallyblocks now always execute even on handler errors - RedirectResponse returning 303 code, instead of 307
v1.3.0
- Added rate limiting with
@rate_limitand@rate_limit_batchdecorators - Added shared manager for multi-worker rate limiting support
- Added support for all HTTP methods: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, TRACE, CONNECT
Installation
pip install altapi
Requirements:
- Python >= 3.10
- uvicorn >= 0.30.0
- anyio >= 4.0.0
- jinja2 >= 3.0.0
- ujson
- Cython >= 3.0.0
Quick Start
Minimal Example
from altapi import AltAPI
from altapi.http import JSONResponse
app = AltAPI()
@app.get("/")
async def home(request):
return JSONResponse({"message": "Hello, World!"})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
Run:
python app.py
Or via uvicorn:
uvicorn app:app --reload
Features
- ✅ ASGI compliant
- ✅ JSON, HTML, and text responses
- ✅ Typed path parameters (
{id:int},{name:str},{value:float},{path:path}) - ✅ Sync and async handlers
- ✅ Full WebSocket support
- ✅ Built-in server (
app.run()) with multi-worker support - ✅ Jinja2 templates
- ✅ Response caching with per-worker InMemoryCache
- ✅ Rate limiting with Shared Memory optimization
- ✅ Dependency Injection with automatic cleanup
- ✅ Request State for middleware-to-handler data passing
- ✅ Static file mounting
- ✅ Optimized Cython router
- ✅ GC optimizations for better performance
- ✅ All HTTP methods: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, TRACE, CONNECT
Usage Examples
Path Parameters
from altapi.http import JSONResponse
@app.get("/users/{id:int}")
async def get_user(request):
user_id = request.path_params["id"] # automatically int
return JSONResponse({"id": user_id, "name": f"User {user_id}"})
@app.get("/items/{name:str}")
async def get_item(request):
name = request.path_params["name"] # str
return JSONResponse({"name": name})
@app.get("/files/{path:path}")
async def get_file(request):
file_path = request.path_params["path"] # captures full path with slashes
return JSONResponse({"path": file_path})
Handling POST Requests
@app.post("/api/echo")
async def echo(request):
data = await request.json()
return JSONResponse({"echo": data})
WebSocket
from altapi.websocket import WebSocket
@app.websocket("/ws/echo")
async def websocket_echo(ws: WebSocket):
await ws.accept()
while True:
text = await ws.receive_text()
await ws.send_text(f"Echo: {text}")
Caching
from altapi.caching import cache
app = AltAPI()
@app.get("/api/data")
@cache(expires=3600) # cache for 1 hour
async def get_data(request):
return JSONResponse({"data": "cached"})
Rate Limiting
from altapi.ratelimit import rate_limit
app = AltAPI()
@app.get("/api/data")
@rate_limit(limit=10, period=60) # 10 requests per minute
async def get_data(request):
return JSONResponse({"data": "value"})
# Multiple limits on same endpoint
from altapi.ratelimit import rate_limit_batch
@app.get("/api/strict")
@rate_limit_batch([
(10, 60), # 10 per minute
(100, 3600), # 100 per hour
(1000, 86400) # 1000 per day
])
async def strict_endpoint(request):
return JSONResponse({"data": "rate limited"})
Dependency Injection
from altapi import AltAPI
from altapi.http import JSONResponse
from altapi.depends import Depends
import sqlite3
def get_db():
"""Generator-based dependency with automatic cleanup."""
conn = sqlite3.connect("app.db")
try:
yield conn
finally:
conn.close()
def get_user_repo(db=Depends(get_db)):
"""Nested dependency."""
return UserRepository(db)
@app.get("/users")
async def list_users(repo=Depends(get_user_repo)):
users = repo.get_all()
return JSONResponse({"users": users})
See full example: examples/database_example.py
Jinja2 Templates
from altapi.templating import Jinja2Templates
app = AltAPI(templates_directory="templates")
templates = Jinja2Templates(directory="templates")
@app.get("/")
async def home(request):
return templates.TemplateResponse(
"index.html",
{"request": request, "title": "Home Page"}
)
Static Files
# Automatically serves files at /static
app = AltAPI(static_directory="static")
Multi-Worker Server
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, workers=4, access_log=True)
Response Types
from altapi.http import (
JSONResponse, # JSON response
HTMLResponse, # HTML response
PlainTextResponse, # Plain text response
StreamingResponse, # Streaming response
FileResponse, # File download with range support
RedirectResponse, # Redirect
)
Documentation
Full documentation is available in DOCS.md.
License
AGPLv3, see LICENSE.txt for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
altapi-1.4.0.tar.gz
(128.6 kB
view details)
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file altapi-1.4.0.tar.gz.
File metadata
- Download URL: altapi-1.4.0.tar.gz
- Upload date:
- Size: 128.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5db1fc88548e0c57815be22b2ab6721c39c1501f36de92c93d552b3ade510a54
|
|
| MD5 |
82de7d2b00f4f223e0bb4c5a161725f1
|
|
| BLAKE2b-256 |
6cc60cf85cbd08f0017d41973caf53b4030ce332d7251c24e264a13be08743e8
|
File details
Details for the file altapi-1.4.0-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: altapi-1.4.0-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 170.7 kB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0ef82449d59aa0fc6e25596f6499291e328fa0525d0e9f4766793def730ecfb7
|
|
| MD5 |
84f3306069f163fae2df138a5381178f
|
|
| BLAKE2b-256 |
cef01b419da1aa474a0f6808b28678ade4b92e9d99a426c8c27cbc041b46944c
|