Skip to main content

lexigram-web

Web layer for Lexigram Framework — ASGI, routing, middleware, and API tooling.


Overview

lexigram-web provides an ASP.NET Core-inspired HTTP layer built on Starlette with constructor injection, a Result-to-HTTP bridge that maps domain errors to status codes automatically, first-class middleware, guard, and filter pipelines, and OpenAPI docs auto-generation.


Full documentation: docs.lexigram.dev

Install

uv add lexigram lexigram-web[granian]

# With optional server backends
uv add "lexigram-web[uvicorn]"   # uvicorn
uv add "lexigram-web[hypercorn]"  # hypercorn
uv add "lexigram-web[security]"   # itsdangerous for signing
uv add "lexigram-web[templates]"  # Jinja2 template support
uv add "lexigram-web[websocket]"  # WebSocket support

Quick Start

from lexigram import Application
from lexigram.di.module import Module, module
from lexigram.web import Controller, WebModule, WebProvider, get


class HelloController(Controller):
    @get("/hello")
    async def hello(self) -> dict[str, str]:
        return {"message": "Hello from Lexigram"}


@module(
    imports=[
        WebModule.configure(
            controllers=[HelloController],
            host="127.0.0.1",
            port=8000,
        )
    ]
)
class AppModule(Module):
    pass


async def main() -> None:
    async with Application.boot(modules=[AppModule]) as app:
        web = await app.container.resolve(WebProvider)
        web.run_server(host="127.0.0.1", port=8000)


if __name__ == "__main__":
    import asyncio

    asyncio.run(main())

Configuration

Zero-config usage: Call WebModule.configure() with no arguments to use all defaults.

Option 1 — YAML file

# application.yaml
web:
  server:
    host: "0.0.0.0"
    port: 8000
    workers: 4
  cors:
    allowed_origins:
      - "https://app.example.com"
  rate_limit:
    enabled: true
    default_limit: "100/minute"

Option 2 — Profiles + Environment Variables (recommended)

export LEX_WEB__SERVER__HOST=0.0.0.0
export LEX_WEB__SERVER__PORT=8080
export LEX_WEB__SECURITY__CORS__ALLOWED_ORIGINS='["https://app.example.com"]'

Option 3 — Python

from lexigram.web import WebModule
from lexigram.web.config import WebConfig, ServerConfig, RateLimitConfig

WebModule.configure(
    controllers=[UserController, OrderController],
    web_config=WebConfig(
        server=ServerConfig(host="0.0.0.0", port=8080, workers=4),
        rate_limit=RateLimitConfig(
            enabled=True,
            default_limit=200,
            default_window=60,
        ),
    ),
)

Config reference

Field Default Env var Description
server.host "0.0.0.0" LEX_WEB__SERVER__HOST Bind host
server.port 8000 LEX_WEB__SERVER__PORT Bind port
server.workers 1 LEX_WEB__SERVER__WORKERS Worker processes
server.reload False LEX_WEB__SERVER__RELOAD Auto-reload on code change
cors.allowed_origins ["http://localhost:3000", "http://localhost:8001"] LEX_WEB__SECURITY__CORS__ALLOWED_ORIGINS CORS allow-list — wildcards blocked in production
rate_limit.enabled True LEX_WEB__RATE_LIMIT__ENABLED Enable rate limiting
rate_limit.default_limit 100 LEX_WEB__RATE_LIMIT__DEFAULT_LIMIT Requests per window
rate_limit.default_window 60 LEX_WEB__RATE_LIMIT__DEFAULT_WINDOW Window in seconds
rate_limit.storage_backend "memory" LEX_WEB__RATE_LIMIT__STORAGE_BACKEND "memory" or "redis"
enable_auth False LEX_WEB__ENABLE_AUTH Enable built-in auth middleware
api_docs.enabled True LEX_WEB__API_DOCS__ENABLED Enable /docs + /redoc
max_body_size 10 MiB LEX_WEB__MAX_BODY_SIZE Request body size limit

Module Factory Methods

Method Description
WebModule.configure(controllers, discover, ...) Configure with controllers and server settings
WebModule.stub() No-op module for unit testing

Key Features

  • Controller pattern — subclass Controller and annotate methods with HTTP decorators
  • Result-to-HTTP bridgeResult[T, DomainError] maps automatically to status codes (404, 422, 403, etc.)
  • HTTP decorators@get, @post, @put, @delete, @patch, @websocket, etc.
  • Auto-discoveryWebModule.configure(discover=["my_app.api.v1"])
  • Middleware pipeline — register ASGI middleware via MiddlewareRegistry
  • Exception filtersDefaultExceptionFilter handles DomainError and HTTPError globally
  • Static files, API docs, debug routes — configurable via WebConfig
  • Rate limiting — per-path rules with memory or Redis storage backend
  • Security — CORS wildcard blocked in production, CSRF enabled by default

Testing

from lexigram import Application
from lexigram.web import WebModule


async def test_controller():
    async with Application.boot(modules=[WebModule.stub()]) as app:
        web = await app.container.resolve(WebProvider)
        assert web.starlette is not None

Key Source Files

File What it contains
src/lexigram/web/module.py WebModule.configure()
src/lexigram/web/di/provider.py WebProvider boot phases
src/lexigram/web/routing/decorators.py HTTP decorators (@get, @post, etc.)
src/lexigram/web/routing/result_bridge.py ResultResponseMapper for Result-to-HTTP mapping
src/lexigram/web/config.py WebConfig, ServerConfig, RateLimitConfig
src/lexigram/web/middleware/__init__.py ASGI middleware classes + MiddlewareRegistry
src/lexigram/web/filters/__init__.py Exception filters

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lexigram_web-0.1.5004.tar.gz (1.1 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lexigram_web-0.1.5004-py3-none-any.whl (298.7 kB view details)

Uploaded Python 3

File details

Details for the file lexigram_web-0.1.5004.tar.gz.

File metadata

  • Download URL: lexigram_web-0.1.5004.tar.gz
  • Upload date:
  • Size: 1.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.14

File hashes

Hashes for lexigram_web-0.1.5004.tar.gz
Algorithm Hash digest
SHA256 c5fc04e7dd219f22300462d1d5d2f36ef67d91ca1466392d09692056734c34f5
MD5 65636bc65dc6a42954e4547b9d2bbd2a
BLAKE2b-256 f96487bbe8fa1dde136c0b7780f85b5937fc177c4b564d22c04afc1717a10269

See more details on using hashes here.

File details

Details for the file lexigram_web-0.1.5004-py3-none-any.whl.

File metadata

File hashes

Hashes for lexigram_web-0.1.5004-py3-none-any.whl
Algorithm Hash digest
SHA256 e6c5746b1c26403783f9e5bcc85c8ce57c2d7db04effa30f4fc30e6f5d3951f2
MD5 1d2a5fe70a98ece5520c8d669d012df4
BLAKE2b-256 ddc570d69e36c33b1eea15ae4f54208db41ffa33c1e6add85407173592e88131

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.5013

1 file

0.1.5007

2 files

This release

0.1.5004 This release

2 files

0.1.5001

2 files

0.1.3007

1 file

0.1.3006

1 file

0.1.3005

1 file

0.1.4

2 files

0.1.2

1 file

0.1.0

2 files

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