dbbasic-web
A Unix-philosophy micro-framework that restores the simplicity of CGI while delivering modern performance (~4000 req/s vs 100 req/s for traditional CGI).
Philosophy
Modern web frameworks moved away from Unix principles and lost key capabilities:
- ❌ Message passing → bolted-on queue systems
- ❌ Cron jobs → separate background job libraries
- ❌ Filesystem routing → giant route tables
- ❌ Flat files → everything forced into SQL
- ❌ Streams → poor SSE/WebSocket support
dbbasic-web restores these capabilities using:
- ✅ Filesystem routing (like CGI, but async)
- ✅ TSV-based storage, queues, and streams (no Redis/SQL required)
- ✅ First-class WebSockets and Server-Sent Events
- ✅ Background jobs with dbbasic-queue
- ✅ Message bus with dbbasic-pipe
- ✅ Flat files alongside databases
Features
1. Filesystem Routing
No route tables. No decorators. Just files:
api/hello.py → handles /hello
api/tasks.py → handles /tasks (collection)
api/tasks/[id].py → handles /tasks/123 (item with pattern matching)
api/users/[username].py → handles /users/alice
templates/about.html → renders /about
public/css/app.css → serves /css/app.css
Use method-specific functions (GET, POST, PUT, DELETE) or generic handle() function.
2. Hierarchical API Handlers
Each handler can manage its own sub-routes:
# api/user.py
def handle(request):
path_parts = request['path_parts'] # ['user', '123', 'edit']
if len(path_parts) == 1:
return list_users()
elif len(path_parts) == 2:
return get_user(path_parts[1])
elif len(path_parts) == 3:
return edit_user(path_parts[1], path_parts[2])
3. TSV-Based Storage (No SQL Required)
from dbbasic_web.storage import write_text, read_text
# Flat files with automatic directory creation
write_text("notes/2024-01-15.txt", "Meeting notes...")
content = read_text("notes/2024-01-15.txt")
4. Background Jobs (No Celery/Redis)
from dbbasic_web.jobs import enqueue
# Jobs stored in TSV files
enqueue("write_flatfile", relpath="exports/data.csv", content=csv_data)
Run worker:
python manage.py worker
5. Message Bus (No Kafka/Redis)
from dbbasic_web.bus import EventBus
bus = EventBus()
await bus.publish("notifications", {"user_id": 123, "event": "login"})
async for message in bus.consume("notifications", group="processors", consumer="worker-1"):
print(message['data'])
6. WebSockets & Server-Sent Events
Built-in, no configuration needed:
WebSocket:
const ws = new WebSocket('ws://localhost:8000/ws/room-name');
ws.send(JSON.stringify({message: 'Hello!'}));
SSE:
const events = new EventSource('/sse/counter');
events.addEventListener('tick', (e) => console.log(e.data));
Quick Start
Installation
pip install dbbasic-web
Or install from source:
git clone https://github.com/askrobots/dbbasic-web.git
cd dbbasic-web
pip install -e .
Run the Server
python manage.py serve
Visit: http://localhost:8000
Project Structure
dbbasic-web/
├── dbbasic_web/
│ ├── api/ # API handlers (filesystem routing)
│ │ ├── hello.py # /hello
│ │ └── user.py # /user, /user/*, /user/*/posts
│ ├── templates/ # Jinja2 templates
│ │ ├── base.html
│ │ └── index.html
│ ├── public/ # Static files
│ │ ├── css/app.css
│ │ └── js/app.js
│ ├── asgi.py # ASGI application
│ ├── router.py # Filesystem router
│ ├── jobs.py # Background jobs
│ ├── bus.py # Message bus
│ ├── storage.py # Flat-file storage
│ ├── websocket.py # WebSocket hub
│ └── sse.py # Server-Sent Events
├── _data/ # Auto-created data directory
│ ├── jobs.tsv # Job queue
│ └── streams/ # Message bus streams
├── manage.py # CLI
└── pyproject.toml
Creating API Endpoints
Simple Endpoint
# api/status.py
import json
from dbbasic_web.responses import json as json_response
def handle(request):
return json_response(json.dumps({"status": "ok"}))
Access: GET /status
REST Resource with Sub-Routes (Classic Pattern)
# api/posts.py
def handle(request):
parts = request['path_parts']
method = request['method']
# /posts
if len(parts) == 1:
if method == 'GET':
return list_posts()
elif method == 'POST':
return create_post(request)
# /posts/123
elif len(parts) == 2:
post_id = parts[1]
if method == 'GET':
return get_post(post_id)
elif method == 'PUT':
return update_post(post_id, request)
# /posts/123/comments
elif len(parts) == 3 and parts[2] == 'comments':
return get_comments(parts[1])
Pattern Routing with Method Functions (New in 0.1.7)
Split routes by file structure and HTTP method for cleaner code:
Collection endpoints:
# api/tasks.py
def GET(request):
"""List all tasks"""
return json(json.dumps({"tasks": [...]}))
def POST(request):
"""Create new task"""
data = json.loads(request.body)
return json(json.dumps({"task": data}), status=201)
Item endpoints with pattern matching:
# api/tasks/[id].py - matches /tasks/123
def GET(request, id):
"""Get single task - id is automatically extracted"""
task = tasks.query_one(id=id)
return json(json.dumps({"task": task}))
def PUT(request, id):
"""Update task"""
data = json.loads(request.body)
tasks.update({'id': id}, data)
return json(json.dumps({"success": True}))
def DELETE(request, id):
"""Delete task"""
tasks.delete(id=id)
return json(json.dumps({"success": True}))
Pattern routing works with any parameter name:
api/users/[username].py → /users/alice → GET(request, username)
api/posts/[slug].py → /posts/hello → GET(request, slug)
api/@[handle].py → /@alice → GET(request, handle)
Benefits:
- File structure mirrors URL structure (
ls api/tasks/shows available routes) - HTTP method = function name (no nested IFs)
- Parameters extracted from URL and passed as function arguments
- Backward compatible (old
handle()pattern still works)
Performance
| Implementation | Requests/sec |
|---|---|
| Traditional CGI | ~100 |
| dbbasic-web | ~4000 |
Achieved by combining:
- Async I/O (ASGI/uvicorn)
- Filesystem routing (no regex matching)
- Direct module imports (no middleware chains)
- TSV files instead of database round-trips
Dependencies
Minimal and purposeful:
uvicorn- ASGI serverjinja2- Templatesdbbasic-tsv- TSV databasedbbasic-queue- Job queuedbbasic-pipe- Message streamsdbbasic-sessions- Authenticationwebsockets- WebSocket support
No Redis. No Celery. No PostgreSQL required.
Commands
# Run development server
python manage.py serve
# Run background job worker
python manage.py worker
# Interactive shell
python manage.py shell
Examples
See complete working examples at dbbasic-examples:
- blog - Simple blog with posts
- microblog - Twitter-like microblog with follows
- api - REST API with Bearer token auth, demonstrating pattern routing
Philosophy in Action
This framework proves that:
- Simplicity scales - Filesystem routing is faster than route tables
- Flat files work - TSV beats Redis for many use cases
- Unix was right - Pipes, files, and processes are enough
- Less is more - 8000 lines total vs 200k+ for Django
License
MIT
Contributing
Built for clarity and hackability. Every module is under 500 lines. Read the source.
Metadata
Release files for dbbasic-web 0.1.11
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| dbbasic_web-0.1.11.tar.gz | 28.5 kB | Without provenance | Details for dbbasic_web-0.1.11.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| dbbasic_web-0.1.11-py3-none-any.whl | Python 3 | none | any | Details for dbbasic_web-0.1.11-py3-none-any.whl |
Total release size: 52.1 kB
Release files / dbbasic_web-0.1.11.tar.gz
| Download URL | dbbasic_web-0.1.11.tar.gz |
|---|---|
| Size | 28.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e361a2a52fa5c958a42da6d12a64fbd462c02e1cd2f2a0537c93e01fb0b0cb90
|
|
BLAKE2b-256 checksum How to use checksums |
17b304dc857befc2ce175741b3e2f05b6013efd26e31099cb3e252f686c939a2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.1
|
Release files / dbbasic_web-0.1.11-py3-none-any.whl
| Download URL | dbbasic_web-0.1.11-py3-none-any.whl |
|---|---|
| Size | 23.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bb567b7e4d6d2fc2c3c684a4b5a1b839a87a42cf53e80d46fc64f85438124112
|
|
BLAKE2b-256 checksum How to use checksums |
971141609b9fbad432f04b6be4a22fd2b18331472fa62527c61838d296eaf219
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.1
|
Security for dbbasic-web 0.1.11
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.