Core Architecture
The HTTP, WebSocket, lifespan, background-task, and process-state architecture behind Flasgo.
Flasgo is built on ASGI and handles http, websocket, and lifespan scopes directly under servers such as Uvicorn.
ASGI foundation
Section titled “ASGI foundation”At the center is the Flasgo application class. Incoming HTTP and WebSocket scopes are wrapped in framework objects, bound to request-local context variables, passed through security controls, and dispatched to the registered endpoint.
That model gives Flasgo:
- Native async request handling
- First-class WebSocket connections and ASGI startup/shutdown
- Compatibility with modern ASGI deployment
- A clean split between request parsing, routing, response coercion, and security enforcement
- Request-local access to
request,session, andcurrent_userwithout sharing state across concurrent tasks
Request flow
Section titled “Request flow”- The ASGI server forwards a request to the
Flasgoapp. Oversized request heads receive431before OpenTelemetry, routing, or session storage; these denials use a locally generated request ID even when incoming IDs are trusted. - Flasgo constructs a
Requestand loads its session with the configured backend; invalid hosts skip shared-storage access. Body reads remain bounded and lazy. - Dispatch validates the Host, with repeated security and authentication failures subject to the configured security-failure rate limit.
- Protected metrics and optional docs endpoints are handled before application routing and never inherit application CORS.
- The router identifies a route-specific CORS policy. A valid preflight can return
204before CSRF checks, middleware, authentication, dependencies, or endpoint code. - CSRF validation runs for ordinary requests, followed by before-request hooks that can short-circuit with a response.
- The router reuses the path/method match from CORS setup when available, or matches again if a before-request hook changed the target. Unmatched paths receive
404and unsupported methods405. Default IP rate limits run before authentication; authorization and identity-based limits follow. A missing or raising authentication backend produces500, not401. - A route-specific endpoint plan binds typed request data, resolves dependencies, and invokes the handler. This includes standalone route/group dependencies and yielding providers.
- Flasgo normalizes the result (enforcing an explicit
response_modelwhen present) and runs after-request hooks. Function-scoped dependencies close before headers are sent. - Flasgo applies eligible CORS and security headers and validates the response before persisting eligible session changes. It then adds framework cookies, validates again, and sends ASGI messages. Streaming responses await transport backpressure and watch for disconnects.
- Request-scoped dependencies close after sending completes or fails. Request context is then cleared. Background tasks run sequentially after successful complete delivery.
After-request hooks run for handler responses and for before-request short-circuits, 404 and 405 responses, rate-limit rejections, and authentication or authorization denials. Host, CSRF, and CORS preflight rejections, metrics and docs endpoint responses, and error-handler responses bypass them.
Failed dispatch restores the loaded session snapshot before invoking an error handler. Only a successfully returning custom error handler can persist deliberate changes from that error path. Returning an explicit error status normally does not roll back session changes. See Session Changes and Failures.
The framework creates a local request ID by default and includes it in the response and structured events. Metrics and OpenTelemetry spans use route templates to keep cardinality bounded; HTTP trace query values are redacted.
WebSocket flow
Section titled “WebSocket flow”- Flasgo rejects oversized request heads before tracing, routing, or session loading, then matches the route.
- Flasgo validates the
Hostheader and exactOrigin, then runs default per-IP route limits before session loading or authentication. - Flasgo loads the session, authenticates the request, and checks route permissions and identity-based rate limits before the handler can call
accept(). - The handler uses bounded text, binary, or JSON message helpers.
- Message size, message rate, message type, JSON validity, subprotocol, and close-frame rules are enforced.
- Connection outcomes and duration are logged and optionally recorded as metrics.
WebSocket sessions are read-only: modifying the session during a connection does not write a cookie through the upgrade handshake.
Lifespan and state
Section titled “Lifespan and state”An application may register one async-generator lifespan handler that yields exactly once. Code before the yield owns startup, while the finally path owns shutdown. Startup failures are reported to the server rather than leaving a partially initialized application, and the app can start again afterward. A handler that yields a second time has its cleanup run immediately and shutdown is reported as failed.
app.state is process-global and is intended for pools, clients, and immutable service objects. Request-specific data belongs in request context. Each worker process has its own state and metrics registry. Route quotas use an in-process limiter by default; the optional RedisRateLimiter coordinates decorated route quotas across workers. Security-failure and WebSocket message throttles remain process-local.
Background work
Section titled “Background work”BackgroundTasks contains in-process best-effort work. Async functions are awaited, synchronous functions run in a thread, failures are logged, and later tasks continue. Durable work belongs on a durable queue.
Response coercion
Section titled “Response coercion”Flasgo accepts several common return shapes and turns them into a response automatically.
| Return value | Result |
|---|---|
str / bytes |
Text or raw body response |
dict / list |
JSON response |
None |
Empty 204 No Content response without Content-Type or Content-Length |
(body, status) |
Response with explicit status, validated like any other response |
(body, status, headers) |
Response with full tuple control |
Response |
Used directly, then prepared with normal security/session processing |
| Dataclass instance | Recursively serialized as JSON, omitting underscore-prefixed fields |
| Streaming response | Sends a bounded async iterable with backpressure |
With an explicit response_model=, output is projected and validated before response coercion; a raw Response cannot bypass that contract. See Response Contracts and Dependency Lifetimes for failure and cleanup boundaries.
Deployment shape
Section titled “Deployment shape”The same app object can be run with the built-in development server for local work or under a production ASGI server for real deployments.
Related docs:
Sources: