Skip to main content

quadkit-web

Quadkit

PyPI Python License

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.

The quadkit family

Package Role
quadkit-contracts zero-dependency protocols, types, exception hierarchy
quadkit the framework core — DI container, modules, config, logging, Result
quadkit-web ASGI layer — controllers, routing, middleware, OpenAPI docs
quadkit-cli project scaffolding and code generators
quadkit-testing in-process test beds, fakes, fixtures

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.

Binding, not parsing

Handler signatures are the validation: query(), path(), header(), cookie(), form(), and body() bind and convert request data to typed values — a DomainModel-annotated parameter validates the whole JSON body, and a malformed request is a 422 with per-field errors before your code runs:

from dataclasses import dataclass

from quadkit.domain import DomainModel
from quadkit.web import Controller, body, get, post, query


@dataclass
class CreateOrder(DomainModel):
    sku: str
    qty: int = 1


class OrdersController(Controller):
    @get("/orders")
    async def list_orders(self, page: int = query(1)) -> dict:
        return {"page": page}  # query param, converted to int

    @post("/orders")
    async def create_order(self, order: CreateOrder = body()) -> dict:
        return {"sku": order.sku, "qty": order.qty}  # validated body

Controllers can also be discovered by package instead of listed — WebModule.configure(discover=["my_app.controllers"]). One security note: cookie-based CSRF is on by default, so JSON clients send the X-CSRF-Token header (or you disable CSRF for token-authenticated APIs: web.security.enable_csrf: false). More composition — middleware, guards, per-route rate limits — in the web API guide and the feature tour.

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 unset → on outside production /docs, /redoc + /openapi.json
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.43 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.43) or a tight range (>=0.0.43,<0.1.0). Full policy: stability and compatibility.

Apache-2.0 — see LICENSE. "Quadkit" and the Quadkit logo are trademarks of the project — see TRADEMARK.md.

Metadata

Release files for quadkit-web 0.0.43

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for quadkit-web 0.0.43
File Size Uploaded Provenance
quadkit_web-0.0.43.tar.gz 1.2 MB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for quadkit-web 0.0.43
File Interpreter ABI Platform
quadkit_web-0.0.43-py3-none-any.whl Python 3 none any Details

Total release size: 2.4 MB

Release files / quadkit_web-0.0.43.tar.gz

Download URL quadkit_web-0.0.43.tar.gz
Size 1.2 MB
Tags Source
SHA-256 checksum
How to use checksums
cd21fdd376b67ea63b2f94610ccbdba48800f9230ef088538cb2d7600988b03a
BLAKE2b-256 checksum
How to use checksums
20b75afc61828d20bb7f7a9c6b3a8948ef2fcaf03b063ab989c2f7f26d598982
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.14

Release files / quadkit_web-0.0.43-py3-none-any.whl

Download URL quadkit_web-0.0.43-py3-none-any.whl
Size 1.2 MB
Tags Python 3
SHA-256 checksum
How to use checksums
b2f6dded15d2a0e764051bd4f9af7a671b8901094dcec9e2ab89bc680b3749c9
BLAKE2b-256 checksum
How to use checksums
a0bdf50eba90526333e92593c714dbc6b9214130b47fc36e830ad6e345e6eb62
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.14

Security for quadkit-web 0.0.43

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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page