dbbasic-web


Namedbbasic-web JSON
Version 0.1.7 PyPI version JSON
download
home_pageNone
SummaryUnixy micro-framework: file routing, SSE/WS, jobs, bus, flat files.
upload_time2025-10-13 11:11:18
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseMIT
keywords web framework cgi unix tsv async asgi
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 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/user.py         → handles /user, /user/123, /user/123/posts
templates/about.html → renders /about
public/css/app.css  → serves /css/app.css
```

### 2. Hierarchical API Handlers
Each handler can manage its own sub-routes:

```python
# 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)
```python
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)
```python
from dbbasic_web.jobs import enqueue

# Jobs stored in TSV files
enqueue("write_flatfile", relpath="exports/data.csv", content=csv_data)
```

Run worker:
```bash
python manage.py worker
```

### 5. Message Bus (No Kafka/Redis)
```python
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:**
```javascript
const ws = new WebSocket('ws://localhost:8000/ws/room-name');
ws.send(JSON.stringify({message: 'Hello!'}));
```

**SSE:**
```javascript
const events = new EventSource('/sse/counter');
events.addEventListener('tick', (e) => console.log(e.data));
```

## Quick Start

### Installation

```bash
pip install dbbasic-web
```

Or install from source:
```bash
git clone https://github.com/askrobots/dbbasic-web.git
cd dbbasic-web
pip install -e .
```

### Run the Server

```bash
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

```python
# 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

```python
# 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])
```

## 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 server
- `jinja2` - Templates
- `dbbasic-tsv` - TSV database
- `dbbasic-queue` - Job queue
- `dbbasic-pipe` - Message streams
- `dbbasic-sessions` - Authentication
- `websockets` - WebSocket support

**No Redis. No Celery. No PostgreSQL required.**

## Commands

```bash
# Run development server
python manage.py serve

# Run background job worker
python manage.py worker

# Interactive shell
python manage.py shell
```

## Philosophy in Action

This framework proves that:
1. **Simplicity scales** - Filesystem routing is faster than route tables
2. **Flat files work** - TSV beats Redis for many use cases
3. **Unix was right** - Pipes, files, and processes are enough
4. **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.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "dbbasic-web",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "web, framework, cgi, unix, tsv, async, asgi",
    "author": null,
    "author_email": "DBBasic Team <hello@dbbasic.com>",
    "download_url": "https://files.pythonhosted.org/packages/57/39/02d1c523db68b77a6b4ef0cbe3c0b681283d861f659488424b4877ee9da3/dbbasic_web-0.1.7.tar.gz",
    "platform": null,
    "description": "# dbbasic-web\n\nA Unix-philosophy micro-framework that restores the simplicity of CGI while delivering modern performance (~4000 req/s vs 100 req/s for traditional CGI).\n\n## Philosophy\n\nModern web frameworks moved away from Unix principles and lost key capabilities:\n- \u274c Message passing \u2192 bolted-on queue systems\n- \u274c Cron jobs \u2192 separate background job libraries\n- \u274c Filesystem routing \u2192 giant route tables\n- \u274c Flat files \u2192 everything forced into SQL\n- \u274c Streams \u2192 poor SSE/WebSocket support\n\n**dbbasic-web restores these capabilities** using:\n- \u2705 Filesystem routing (like CGI, but async)\n- \u2705 TSV-based storage, queues, and streams (no Redis/SQL required)\n- \u2705 First-class WebSockets and Server-Sent Events\n- \u2705 Background jobs with dbbasic-queue\n- \u2705 Message bus with dbbasic-pipe\n- \u2705 Flat files alongside databases\n\n## Features\n\n### 1. Filesystem Routing\nNo route tables. No decorators. Just files:\n\n```\napi/hello.py        \u2192 handles /hello\napi/user.py         \u2192 handles /user, /user/123, /user/123/posts\ntemplates/about.html \u2192 renders /about\npublic/css/app.css  \u2192 serves /css/app.css\n```\n\n### 2. Hierarchical API Handlers\nEach handler can manage its own sub-routes:\n\n```python\n# api/user.py\ndef handle(request):\n    path_parts = request['path_parts']  # ['user', '123', 'edit']\n\n    if len(path_parts) == 1:\n        return list_users()\n    elif len(path_parts) == 2:\n        return get_user(path_parts[1])\n    elif len(path_parts) == 3:\n        return edit_user(path_parts[1], path_parts[2])\n```\n\n### 3. TSV-Based Storage (No SQL Required)\n```python\nfrom dbbasic_web.storage import write_text, read_text\n\n# Flat files with automatic directory creation\nwrite_text(\"notes/2024-01-15.txt\", \"Meeting notes...\")\ncontent = read_text(\"notes/2024-01-15.txt\")\n```\n\n### 4. Background Jobs (No Celery/Redis)\n```python\nfrom dbbasic_web.jobs import enqueue\n\n# Jobs stored in TSV files\nenqueue(\"write_flatfile\", relpath=\"exports/data.csv\", content=csv_data)\n```\n\nRun worker:\n```bash\npython manage.py worker\n```\n\n### 5. Message Bus (No Kafka/Redis)\n```python\nfrom dbbasic_web.bus import EventBus\n\nbus = EventBus()\nawait bus.publish(\"notifications\", {\"user_id\": 123, \"event\": \"login\"})\n\nasync for message in bus.consume(\"notifications\", group=\"processors\", consumer=\"worker-1\"):\n    print(message['data'])\n```\n\n### 6. WebSockets & Server-Sent Events\nBuilt-in, no configuration needed:\n\n**WebSocket:**\n```javascript\nconst ws = new WebSocket('ws://localhost:8000/ws/room-name');\nws.send(JSON.stringify({message: 'Hello!'}));\n```\n\n**SSE:**\n```javascript\nconst events = new EventSource('/sse/counter');\nevents.addEventListener('tick', (e) => console.log(e.data));\n```\n\n## Quick Start\n\n### Installation\n\n```bash\npip install dbbasic-web\n```\n\nOr install from source:\n```bash\ngit clone https://github.com/askrobots/dbbasic-web.git\ncd dbbasic-web\npip install -e .\n```\n\n### Run the Server\n\n```bash\npython manage.py serve\n```\n\nVisit: http://localhost:8000\n\n### Project Structure\n\n```\ndbbasic-web/\n\u251c\u2500\u2500 dbbasic_web/\n\u2502   \u251c\u2500\u2500 api/              # API handlers (filesystem routing)\n\u2502   \u2502   \u251c\u2500\u2500 hello.py      # /hello\n\u2502   \u2502   \u2514\u2500\u2500 user.py       # /user, /user/*, /user/*/posts\n\u2502   \u251c\u2500\u2500 templates/        # Jinja2 templates\n\u2502   \u2502   \u251c\u2500\u2500 base.html\n\u2502   \u2502   \u2514\u2500\u2500 index.html\n\u2502   \u251c\u2500\u2500 public/           # Static files\n\u2502   \u2502   \u251c\u2500\u2500 css/app.css\n\u2502   \u2502   \u2514\u2500\u2500 js/app.js\n\u2502   \u251c\u2500\u2500 asgi.py           # ASGI application\n\u2502   \u251c\u2500\u2500 router.py         # Filesystem router\n\u2502   \u251c\u2500\u2500 jobs.py           # Background jobs\n\u2502   \u251c\u2500\u2500 bus.py            # Message bus\n\u2502   \u251c\u2500\u2500 storage.py        # Flat-file storage\n\u2502   \u251c\u2500\u2500 websocket.py      # WebSocket hub\n\u2502   \u2514\u2500\u2500 sse.py            # Server-Sent Events\n\u251c\u2500\u2500 _data/                # Auto-created data directory\n\u2502   \u251c\u2500\u2500 jobs.tsv          # Job queue\n\u2502   \u2514\u2500\u2500 streams/          # Message bus streams\n\u251c\u2500\u2500 manage.py             # CLI\n\u2514\u2500\u2500 pyproject.toml\n```\n\n## Creating API Endpoints\n\n### Simple Endpoint\n\n```python\n# api/status.py\nimport json\nfrom dbbasic_web.responses import json as json_response\n\ndef handle(request):\n    return json_response(json.dumps({\"status\": \"ok\"}))\n```\n\nAccess: `GET /status`\n\n### REST Resource with Sub-Routes\n\n```python\n# api/posts.py\ndef handle(request):\n    parts = request['path_parts']\n    method = request['method']\n\n    # /posts\n    if len(parts) == 1:\n        if method == 'GET':\n            return list_posts()\n        elif method == 'POST':\n            return create_post(request)\n\n    # /posts/123\n    elif len(parts) == 2:\n        post_id = parts[1]\n        if method == 'GET':\n            return get_post(post_id)\n        elif method == 'PUT':\n            return update_post(post_id, request)\n\n    # /posts/123/comments\n    elif len(parts) == 3 and parts[2] == 'comments':\n        return get_comments(parts[1])\n```\n\n## Performance\n\n| Implementation | Requests/sec |\n|---------------|--------------|\n| Traditional CGI | ~100 |\n| dbbasic-web | ~4000 |\n\nAchieved by combining:\n- Async I/O (ASGI/uvicorn)\n- Filesystem routing (no regex matching)\n- Direct module imports (no middleware chains)\n- TSV files instead of database round-trips\n\n## Dependencies\n\nMinimal and purposeful:\n- `uvicorn` - ASGI server\n- `jinja2` - Templates\n- `dbbasic-tsv` - TSV database\n- `dbbasic-queue` - Job queue\n- `dbbasic-pipe` - Message streams\n- `dbbasic-sessions` - Authentication\n- `websockets` - WebSocket support\n\n**No Redis. No Celery. No PostgreSQL required.**\n\n## Commands\n\n```bash\n# Run development server\npython manage.py serve\n\n# Run background job worker\npython manage.py worker\n\n# Interactive shell\npython manage.py shell\n```\n\n## Philosophy in Action\n\nThis framework proves that:\n1. **Simplicity scales** - Filesystem routing is faster than route tables\n2. **Flat files work** - TSV beats Redis for many use cases\n3. **Unix was right** - Pipes, files, and processes are enough\n4. **Less is more** - 8000 lines total vs 200k+ for Django\n\n## License\n\nMIT\n\n## Contributing\n\nBuilt for clarity and hackability. Every module is under 500 lines. Read the source.\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Unixy micro-framework: file routing, SSE/WS, jobs, bus, flat files.",
    "version": "0.1.7",
    "project_urls": {
        "Documentation": "https://github.com/dbbasic/dbbasic-web",
        "Homepage": "https://dbbasic.com",
        "Issues": "https://github.com/dbbasic/dbbasic-web/issues",
        "Repository": "https://github.com/dbbasic/dbbasic-web"
    },
    "split_keywords": [
        "web",
        " framework",
        " cgi",
        " unix",
        " tsv",
        " async",
        " asgi"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "d1c8d3ed939bb83f50cf5b82ad0215d4fe0133f54097c1c22bbb2761c71e27cd",
                "md5": "a20e32a46257ace4600218168e4f2836",
                "sha256": "bebee7f8725587429cfbdaed2c9c0e0a6472c2ad40d80c1115005f67410fa46e"
            },
            "downloads": -1,
            "filename": "dbbasic_web-0.1.7-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "a20e32a46257ace4600218168e4f2836",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 21267,
            "upload_time": "2025-10-13T11:11:16",
            "upload_time_iso_8601": "2025-10-13T11:11:16.861474Z",
            "url": "https://files.pythonhosted.org/packages/d1/c8/d3ed939bb83f50cf5b82ad0215d4fe0133f54097c1c22bbb2761c71e27cd/dbbasic_web-0.1.7-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "573902d1c523db68b77a6b4ef0cbe3c0b681283d861f659488424b4877ee9da3",
                "md5": "86e81da7e5398d0a90dbcf4e700f01bf",
                "sha256": "89def6a0beee4c29990502b5c7aa967897d224ada47fe4551a3869e570cde797"
            },
            "downloads": -1,
            "filename": "dbbasic_web-0.1.7.tar.gz",
            "has_sig": false,
            "md5_digest": "86e81da7e5398d0a90dbcf4e700f01bf",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 20496,
            "upload_time": "2025-10-13T11:11:18",
            "upload_time_iso_8601": "2025-10-13T11:11:18.017878Z",
            "url": "https://files.pythonhosted.org/packages/57/39/02d1c523db68b77a6b4ef0cbe3c0b681283d861f659488424b4877ee9da3/dbbasic_web-0.1.7.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-13 11:11:18",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "dbbasic",
    "github_project": "dbbasic-web",
    "github_not_found": true,
    "lcname": "dbbasic-web"
}
        
Elapsed time: 2.00373s