Architecture and design

MicroPie is intentionally small. Its goal is to provide just enough functionality to build asynchronous web applications without locking you into a rigid structure. This section discusses some of the key design choices and how they influence the API.

ASGI application

MicroPie is built on top of the ASGI specification, which defines how Python applications communicate with asynchronous servers. Your application subclass inherits from App and implements the ASGI call interface via the __call__ method. The framework inspects the scope['type'] field to dispatch to HTTP, WebSocket or lifespan handling code.

Routing by naming

Unlike frameworks that require you to declare routes in advance, MicroPie derives routing information from the names of your methods. The first segment of the path becomes the handler name. This allows you to add new endpoints simply by defining a new method on your application subclass. The remaining path segments, query string parameters and form data are mapped to arguments via function signature inspection. This approach reduces boilerplate but may surprise users expecting explicit routing. You can always regain control by writing a custom middleware to map paths to handlers or by checking self.request.method and self.request.path_params inside your handlers.

Context‑local request

MicroPie stores the current request in a contextvars ContextVar. This allows you to access self.request within your handler as well as from deeper helper functions without passing the request around explicitly. The context variable is reset at the end of each request to avoid leaking state.

Session management

Sessions are stored in a pluggable back‑end and identified by a random session_id cookie. The default in‑memory back‑end keeps session data in dictionaries keyed by session ID and updates a last access timestamp to implement expiration. You can customise the back‑end by providing your own implementation of SessionBackend. MicroPie saves sessions after a handler returns, only if self.request.session is non‑empty, to avoid creating unnecessary cookies.

Middleware pipeline

The middleware hooks allow you to intercept requests before and after handlers. Middleware can modify the request object, provide early responses (useful for authentication), and alter the final response. For WebSockets, separate middleware hooks run before the connection handler starts and after it finishes.

Streaming and SSE support

Handlers may return an iterator or asynchronous generator to stream data to the client. MicroPie detects such responses and iterates over them, sending each chunk to the client. When using server‑sent events (SSE) there is an additional challenge: if the client disconnects, the iterator must be cancelled. MicroPie wraps SSE responses in a small loop that listens for disconnect events and cancels the generator accordingly. Remember to include a Content‑Type: text/event-stream header when sending SSE.

Lifespan hooks

ASGI defines a lifespan protocol for startup and shutdown events. MicroPie exposes startup_handlers and shutdown_handlers lists on the App instance. Handlers are executed sequentially and should be asynchronous callables. Use them to open database connections, prime caches or register background tasks. Lifespan functions run before any request or WebSocket traffic is accepted, ensuring your dependencies are ready.

Templating and JSON helpers

If jinja2 is installed, MicroPie enables the _render_template() helper to render templates from a templates directory, returning HTML responses with the correct Content-Type. For JSON, the framework prefers orjson when available and gracefully falls back to json. This keeps the core lean while letting you opt into performance boosts.

Error handling

MicroPie automatically handles common error cases. Requests for unknown routes result in a 404 Not Found. If a required parameter is missing, MicroPie responds with 400 Bad Request. Unhandled exceptions inside handlers produce a 500 Internal Server Error and are printed to standard error. You can override these behaviours via middleware.

Extensibility

The minimalist core is designed to be extended. You can mount your application behind other ASGI middleware, integrate additional protocols like Socket.IO, or implement your own session storage. The framework imposes few constraints so that you remain in control of your stack.

WebSocket pipeline

WebSocket connections follow a parallel flow to HTTP requests. The ws_ method naming convention resolves handlers, middleware gates the connection before accept() is called, and the WebSocket helper manages receive/send coroutines. Session data is shared with HTTP handlers so users can authenticate once and reuse the same session across protocols.