quadkit-web
The async web layer for Quadkit: controllers with signature-based
binding, a Result-to-HTTP bridge, middleware pipelines, and generated
OpenAPI docs — built on Starlette, server-backend agnostic.
For application developers building HTTP services: define controllers, attach the web module, and serve on Granian, Uvicorn, or Hypercorn.
Installation
The distribution ships no server by itself — install one backend (or
use quadkit[web], which resolves to quadkit-web[granian]):
uv add "quadkit-web[granian]" # default backend, ASGI
uv add "quadkit-web[uvicorn]" # alternative backend
uv add "quadkit-web[hypercorn]" # alternative backend
Requires Python >= 3.11.
Minimal working example
from quadkit import Application
from quadkit.web import Controller, WebModule, get
from quadkit.web.server import run_server
class HelloController(Controller):
@get("/hello")
async def hello(self, name: str = "world") -> dict:
return {"message": f"hello, {name}"}
def create_app() -> Application:
app = Application()
app.add_modules([WebModule.configure(controllers=[HelloController])])
return app
if __name__ == "__main__":
run_server(create_app(), port=8000)
/hello is yours; /docs, /redoc, /openapi.json, and /health
come with it. Full walkthrough:
your first app, then the
web API guide.
Optional extras
| Extra | Contents |
|---|---|
[granian] / [uvicorn] / [hypercorn] |
ASGI server backends |
[security] |
itsdangerous — signed tokens |
[templates] |
Jinja2 template rendering |
[websocket] |
websockets — WebSocket support |
[client] |
HTTP client |
[test] / [docs] / [dev] / [all] |
tooling bundles |
Public API entry points
from quadkit.web import (
Controller, WebModule,
get, post, put, patch, delete,
body, query, path, header, cookie, form,
HTTPError, error_status,
JSONResponse, HTMLResponse, StreamingResponse, FileResponse,
RedirectResponse, BackgroundTasks,
)
from quadkit.web.config import WebConfig, ServerConfig, RateLimitConfig
from quadkit.web.middleware import MiddlewareRegistry
from quadkit.web.server import run_server, run_server_async
WebModule.configure(controllers=..., middleware=...) is the assembly
point; WebModule.stub() gives a no-op web module for unit tests.
Configuration
Everything is typed, validated at boot, and env-overridable
(QK_WEB__...):
| YAML path | Default | What it controls |
|---|---|---|
web.server.host / port |
0.0.0.0 / 8000 |
bind address |
web.server.backend |
granian |
granian, uvicorn, or hypercorn |
web.server.workers |
1 |
worker processes (production lever) |
web.server.reload |
false |
hot reload (development aid) |
web.security.enable_csrf |
true |
cookie-based CSRF protection |
web.security.cors.allowed_origins |
[] (deny-by-default) |
CORS allow-list |
web.rate_limit.enabled |
false |
opt-in rate limiting |
web.api_docs.enabled |
true |
/docs + /redoc |
web.max_body_size |
10 MiB | request body cap |
Env overrides mirror the YAML path, e.g. QK_WEB__SERVER__PORT=8080,
QK_WEB__SECURITY__CORS__ALLOWED_ORIGINS='["https://app.example.com"]'.
See configuration.
Error handling
Every failure renders as an RFC 7807 problem body: domain exceptions map
through a status table, HTTPError gives direct control, request-body
validation answers 422 with per-field errors.
The error-handling guide shows
all three paths with executable examples.
Testing
quadkit-testing's WebTestBed boots your app in-process and asserts
on responses — no listening socket, no mocking:
async def test_hello() -> None:
from quadkit.testing import WebTestBed
async with WebTestBed(create_app()) as bed:
response = bed.get("/hello", params={"name": "quadkit"})
response.assert_status(200)
assert response.json == {"message": "hello, quadkit"}
Security
Conservative defaults: CSRF on, CORS deny-by-default, unexpected exceptions contained to a minimal 500 body. Details and hardening: secure configuration; report vulnerabilities privately per SECURITY.md.
Stability
Version 0.0.3 in the 0.x series, released in lockstep with the
other four distributions; APIs may change between minor versions until
1.0 — pin an exact version (quadkit-web==0.0.3) or a tight range
(>=0.0.3,<0.1.0). Full policy:
stability and compatibility.
Release files for quadkit-web 0.0.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| quadkit_web-0.0.3.tar.gz | 379.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| quadkit_web-0.0.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 704.1 kB
Release files / quadkit_web-0.0.3.tar.gz
| Download URL | quadkit_web-0.0.3.tar.gz |
|---|---|
| Size | 379.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0eab695daf57c0013342033c958c87124a522fdeb5cdf94174e7b6b834a119fa
|
|
BLAKE2b-256 checksum How to use checksums |
12c4a3f9f770ba7bd7e07326f9cf4f80caee68e11c27340d0ab3adecfed5166a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.8.14
|
Release files / quadkit_web-0.0.3-py3-none-any.whl
| Download URL | quadkit_web-0.0.3-py3-none-any.whl |
|---|---|
| Size | 324.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ca61ed70e5002cfde0867448e72b938c98996a874e1f0fc272f8da71fb6aee69
|
|
BLAKE2b-256 checksum How to use checksums |
da076215f7c6d66bc18c37e76529185177eb3f19cba387996b6eedc43f51defa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.8.14
|