Gravier
Small typed wrapper around granian's RSGI interface: a router with msgspec validation, app lifecycle, SSE helpers, OpenAPI generation, and test utilities.
pip install gravier
Quick start
import msgspec
from gravier import App, Body, Query, Response, Router, serve
class SearchQuery(msgspec.Struct):
q: str
limit: int = 10
class CreateItem(msgspec.Struct):
name: str
price: float
router = Router()
@router.get("/health")
async def health(scope, proto) -> dict:
return {"status": "ok"}
@router.get("/items/{item_id}")
async def get_item(scope, proto, item_id: str) -> dict:
return {"item_id": item_id}
@router.get("/search")
async def search(query: Query[SearchQuery]) -> dict:
return {"q": query.q, "limit": query.limit}
@router.post("/items")
async def create(req: Body[CreateItem]) -> dict: # 422 on invalid body
return {"name": req.name}
app = App(router, on_startup=[], on_shutdown=[])
Serve it (main.py above):
granian --interface rsgi main:app
or programmatically, with a clean error when the port is taken:
from gravier import serve
serve("main:app", port=8000)
Features
-
Router — static and
{param}routes,GET/POST/PUT/PATCH/DELETE,include(other, prefix=...), JSON errors for 404/405/422/500. -
Query[T]/Body[T]— msgspec-validated query strings and JSON bodies; pyright sees the concreteTon the parameter. Invalid input returns 422 automatically. -
Depends— inject sync callables, coroutines, or async generators (setup/teardown) into handlers. -
App— bundles a router with startup/shutdown hooks mapped onto granian's__rsgi_init__/__rsgi_del__worker lifecycle. -
SSE —
sse(event, data)formatting and ready-madeSSE_HEADERS; a handler returningNonekeeps the protocol to itself:from gravier import SSE_HEADERS, sse @router.post("/events") async def events(scope, proto) -> None: transport = proto.response_stream(200, SSE_HEADERS) await transport.send_bytes(sse("delta", {"text": "hello"}))
-
OpenAPI —
build_openapi(router, title=...)generates a 3.1 spec fromQuery/Body/return annotations;openapi_handler(router, title=...)serves it. -
Testing (
gravier.testing) —FakeScope/FakeProtofor direct handler tests (including captured streams), andASGIBridgeto run the router under any ASGI test client without booting granian:import niquests from gravier.testing import ASGIBridge with niquests.Session(app=ASGIBridge(router)) as client: assert client.get("http://test/health").json() == {"status": "ok"}
Development
uv sync --group dev
just ci # lint + type check + tests
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
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 gravier-0.1.0.tar.gz.
File metadata
- Download URL: gravier-0.1.0.tar.gz
- Upload date:
- Size: 11.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
180958d5962bcf2544be4ba86d3dbefe1ca29fa8bceb5158dd7605b7a075a8f1
|
|
| MD5 |
26385b7fbbed53fb9c4df785cb5e13a5
|
|
| BLAKE2b-256 |
e4b8caf67ecfdce96242e1af865ea500e8ddad08d06becc6160e5668756de68d
|
File details
Details for the file gravier-0.1.0-py3-none-any.whl.
File metadata
- Download URL: gravier-0.1.0-py3-none-any.whl
- Upload date:
- Size: 14.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5458a888cf1f8464e9bb2c3252c03742302b9e6abdeb197aff9d596e3fed9196
|
|
| MD5 |
5819ff9196eabb6d563ea17d836d3d2c
|
|
| BLAKE2b-256 |
b662856b141abf19985061a5ced485bd9cd78c9f0e6a29e3a4a2f438ece43e4e
|