Metadata-Version: 2.4
Name: mm-web
Version: 0.1.1
Summary: MetaMessage protocol integrations for Python web frameworks
Project-URL: Homepage, https://github.com/metamessage/mm-web-py
Project-URL: Documentation, https://github.com/metamessage/mm-web-py#readme
Project-URL: Repository, https://github.com/metamessage/mm-web-py
Project-URL: Issues, https://github.com/metamessage/mm-web-py/issues
Author: mm-web-py contributors
License: MIT
Keywords: fastapi,flask,metamessage,mm,protocol,serialization
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Classifier: Programming Language :: Python :: 3.16
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: build>=1.5.1
Requires-Dist: httpx>=0.24.0
Requires-Dist: metamessage>=0.2.10
Requires-Dist: twine>=6.2.0
Provides-Extra: dev
Requires-Dist: django>=5.2.15; extra == 'dev'
Requires-Dist: fastapi>=0.136.3; extra == 'dev'
Requires-Dist: flask>=3.1.3; extra == 'dev'
Requires-Dist: mypy>=1.0.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Provides-Extra: django
Requires-Dist: django>=5.2.15; extra == 'django'
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.136.3; extra == 'fastapi'
Provides-Extra: flask
Requires-Dist: flask>=3.1.3; extra == 'flask'
Description-Content-Type: text/markdown

# mm-web

MetaMessage protocol integrations for Python web frameworks — framework adapters
for **FastAPI**, **Flask**, and **Django**, plus a framework-agnostic HTTP client SDK.

Install from PyPI.

The wheel ships **all** adapter code — you only need to install the web framework
itself as a runtime dependency. Use extras for a one-command install, or install
them separately:

```bash
# --- pip ---
pip install "mm-web[fastapi]"              # mm-web + FastAPI  (一条命令)
pip install "mm-web[flask]"                # mm-web + Flask
pip install "mm-web[django]"               # mm-web + Django
pip install "mm-web[dev]"                  # mm-web + 全部框架 + 开发工具

# pip 两条命令（wheel 已包含适配器代码，仅缺框架运行时）:
pip install mm-web
pip install fastapi                        # 或 flask / django

# --- uv ---
uv add "mm-web[fastapi]"                   # mm-web + FastAPI  (一条命令)
uv add "mm-web[flask]"
uv add "mm-web[django]"

# uv 两条命令:
uv add mm-web
uv add fastapi                             # 或 flask / django
```

## What is MetaMessage?

[MetaMessage](https://github.com/metamessage/metamessage) is a binary serialization
protocol that provides efficient encoding/decoding of structured data. It follows
the convention:

- **GET/DELETE** requests: Parameters are hex-encoded as `?data=<hex>` query parameter
- **POST/PUT/PATCH** requests: Body is binary MetaMessage
- **Responses**: Always binary MetaMessage

## Packages

### mm-core

Shared framework-agnostic code:

- `CONTENT_TYPE_METAMESSAGE` - Content type constant (`application/metamessage`)
- `MMEncoderError` / `MMDecoderError` - Encoding/decoding error classes
- `MMClient` / `AsyncMMClient` - Synchronous and asynchronous HTTP clients

### mm-fastapi

```python
from fastapi import FastAPI
from mm_fastapi import MMRouter

app = FastAPI()
router = MMRouter(app)

@router.get("/users")
async def list_users(req: User) -> User:
    return User(name=req.name, age=req.age)

@router.post("/users")
async def create_user(req: User) -> User:
    return User(name=req.name, age=req.age)
```

### mm-flask

```python
from flask import Flask
from mm_flask import MMFlask, MMMiddleware

app = Flask(__name__)
MMMiddleware(app)
mm = MMFlask(app)

@mm.get("/users")
def list_users(req: User) -> User:
    return User(name=req.name, age=req.age)

@mm.post("/users")
def create_user(req: User) -> User:
    return User(name=req.name, age=req.age)
```

### mm-django

```python
from django.http import HttpResponse
from mm_django import mm_view

@mm_view()
def create_user(request, req: User) -> User:
    return User(name=req.name, age=req.age)
```

## Schema discovery & validation

Every route automatically exposes an `OPTIONS` endpoint that returns the request
schema encoded as binary MetaMessage, along with two headers:

- `Access-Control-Max-Age: 86400`
- `Schema-Md5: <md5 of the example-encoded schema>`

The `mm_core.MMClient` uses these: it sends an `OPTIONS` preflight, caches the
`Schema-Md5`, and sends it back on each request. The server validates the incoming
`Schema-Md5` header and rejects mismatches with a `{"error": "Schema-Md5 mismatch: ..."}`
response, so clients can detect an out-of-date schema before sending data.

## Quick start (end-to-end)

A complete, runnable walkthrough lives in
[`examples/mm-fastapi/run.py`](examples/mm-fastapi/run.py). It spins up the FastAPI
app in-process and exercises health, `OPTIONS` schema discovery, `GET` query
encoding, `POST`/`PUT`/`DELETE` body encoding, and `Schema-Md5` validation:

```bash
cd examples/mm-fastapi
python run.py
```

You can also run a real server + client (in two terminals):

```bash
# terminal 1
cd examples/mm-fastapi
python server_example.py

# terminal 2
cd examples/mm-fastapi
python client_example.py
```

## Testing

```bash
pip install "mm-web[dev]"
pytest tests/ -v
```

## Project Structure

```
src/
├── mm_core/           # Shared types, errors, client SDK
├── mm_fastapi/        # FastAPI integration
├── mm_flask/          # Flask integration
└── mm_django/         # Django integration
tests/
├── test_mm_django.py
├── test_mm_fastapi.py
└── test_mm_flask.py
examples/
├── mm-fastapi/        # FastAPI examples (server_example, client_example, run.py)
├── mm-flask/          # Flask examples
└── mm_django/         # Django examples
```

## License

MIT License