ASGI Fundamentals¶
ASGI is the contract between Palfrey and your application.
The Three Inputs Every ASGI App Receives¶
scope: metadata about protocol and connection contextreceive: async callable yielding inbound messagessend: async callable accepting outbound messages
Minimal app example:
from __future__ import annotations
async def app(scope, receive, send):
"""Serve HTTP and reject unknown protocols."""
if scope["type"] != "http":
raise RuntimeError(f"Unsupported scope type: {scope['type']}")
await send(
{
"type": "http.response.start",
"status": 200,
"headers": [(b"content-type", b"text/plain; charset=utf-8")],
}
)
await send({"type": "http.response.body", "body": b"ASGI app is running"})
Scope inspector example:
from __future__ import annotations
import json
async def app(scope, receive, send):
"""Return protocol metadata useful during debugging."""
if scope["type"] != "http":
return
payload = {
"type": scope["type"],
"method": scope.get("method"),
"path": scope.get("path"),
"root_path": scope.get("root_path"),
"client": scope.get("client"),
"server": scope.get("server"),
"scheme": scope.get("scheme"),
}
body = json.dumps(payload, indent=2, default=str).encode("utf-8")
await send(
{
"type": "http.response.start",
"status": 200,
"headers": [
(b"content-type", b"application/json"),
(b"content-length", str(len(body)).encode("ascii")),
],
}
)
await send({"type": "http.response.body", "body": body})
Scope by Protocol¶
HTTP scope¶
Typical fields:
type = "http"methodpath,raw_path,query_stringheadersclient,server
WebSocket scope¶
Typical fields:
type = "websocket"subprotocolsextensions- shared network/path/header fields
Lifespan scope¶
Typical fields:
type = "lifespan"- app startup/shutdown channel
Message Sequences¶
HTTP¶
- app receives one or more
http.request - app sends
http.response.start - app sends one or more
http.response.body
WebSocket¶
- app receives
websocket.connect - app sends
websocket.acceptorwebsocket.close - app and client exchange messages
- disconnect/close completes session
Lifespan¶
- app receives startup event
- app initializes shared resources
- app receives shutdown event
- app releases resources
Common ASGI Mistakes¶
- not sending
http.response.startbefore body - returning non-
Nonefrom ASGI app - sending websocket messages before
websocket.accept - assuming headers are strings instead of bytes
Why engineers care¶
ASGI correctness directly affects interoperability and reliability.
Why non-technical stakeholders should care¶
A standard contract reduces integration risk and speeds migration between frameworks and runtimes.