clika_runtime.http
Serve HTTP from Python: routes, middleware, static files, streamed replies.
An :class:HttpServer takes handlers for exact paths and for patterns with
captures, runs them on its own threads, and answers with the
:class:Response a handler returns::
from clika_runtime import http
server = http.HttpServer()
@server.get("/health")
def health(request: http.Request) -> dict[str, str]:
return {"status": "ok"} # a dict is sent as JSON
@server.route("GET", r"/models/(?P<name>[^/]+)", pattern=True)
def model(request: http.Request) -> str:
return f"model {request.param('name')}" # a str is sent as text/plain
@server.post("/echo")
def echo(request: http.Request) -> http.Response:
return http.Response.bytes(request.body, "application/octet-stream")
with server:
port = server.bind_to_any_port("127.0.0.1")
... # the block ends with server.stop()
A handler returns a :class:Response (built with Response.text,
.json, .html, .bytes, .error, .redirect, .file,
.stream or .sse), a str (sent as text/plain) or a dict /
list (serialized with json.dumps and sent as application/json).
A streamed body pulls its chunks from a generator::
@server.get("/events")
def events(request: http.Request) -> http.Response:
def frames():
for i in range(3):
yield {"event": "tick", "data": str(i)}
return http.Response.sse(frames())
The :class:Request a handler receives is a view over the request the
server is handling: read it during the call; a read after the handler
returned raises RuntimeError.
Middleware wraps every route: middleware(request, next) inspects the
request, then returns next() (the downstream response, changed or not)
or its own response without calling next. Register middleware, routes
and mounts before the server listens.
A handler that raises answers an opaque 500; the exception's text reaches
the handler installed with :meth:HttpServer.set_exception_handler as
what (do not echo it to clients) and the server keeps serving.
Threading: listen blocks its thread until stop is called from
another; listen_async and bind_to_any_port serve on the server's
own thread. Every one of them, and stop and wait_until_ready,
releases the interpreter lock while it waits, so other Python threads keep
running. A handler holds the lock only while it runs Python code, so
several handlers make progress at once whenever they wait on I/O or on the
runtime.
| Name | Kind |
|---|---|
FormFile | class |
FormPart | class |
HttpServer | class |
Method | class |
Next | class |
Request | class |
Response | class |
RouteGroup | class |