# ASGI Type Definitions

Complete type definitions for ASGI (Asynchronous Server Gateway Interface) protocol. These TypedDict classes and type aliases provide type-safe interfaces for building ASGI applications, middleware, and servers.

## Imports

```python
from uvicorn._types import (
    # ASGI Application Types
    ASGIApplication,
    ASGI2Application,
    ASGI3Application,
    ASGI2Protocol,
    # Scope Types
    Scope,
    WWWScope,
    HTTPScope,
    WebSocketScope,
    LifespanScope,
    ASGIVersions,
    # Callable Types
    ASGIReceiveCallable,
    ASGISendCallable,
    # Event Types
    ASGIReceiveEvent,
    ASGISendEvent,
    WebSocketEvent,
    # HTTP Event Types
    HTTPRequestEvent,
    HTTPResponseStartEvent,
    HTTPResponseBodyEvent,
    HTTPResponseTrailersEvent,
    HTTPServerPushEvent,
    HTTPDisconnectEvent,
    HTTPResponseDebugEvent,
    # WebSocket Event Types
    WebSocketConnectEvent,
    WebSocketAcceptEvent,
    WebSocketReceiveEvent,
    WebSocketSendEvent,
    WebSocketResponseStartEvent,
    WebSocketResponseBodyEvent,
    WebSocketDisconnectEvent,
    WebSocketCloseEvent,
    # Lifespan Event Types
    LifespanStartupEvent,
    LifespanShutdownEvent,
    LifespanStartupCompleteEvent,
    LifespanStartupFailedEvent,
    LifespanShutdownCompleteEvent,
    LifespanShutdownFailedEvent,
    # WSGI Types
    WSGIApp,
    Environ,
    StartResponse,
    ExcInfo,
)
```

## ASGI Application Types

### Application Interfaces

```python { .api }
# Union of ASGI2 and ASGI3 application types
ASGIApplication = Union[ASGI2Application, ASGI3Application]

# ASGI3 application callable
ASGI3Application = Callable[
    [Scope, ASGIReceiveCallable, ASGISendCallable],
    Awaitable[None],
]

# ASGI2 application class type
ASGI2Application = type[ASGI2Protocol]
```

### ASGI2 Protocol

```python { .api }
class ASGI2Protocol(Protocol):
    """
    Protocol definition for ASGI2 application classes.

    ASGI2 uses a class-based interface where the application is
    instantiated with the scope, then called with receive and send.
    """

    def __init__(self, scope: Scope) -> None:
        """
        Initialize with connection scope.

        Args:
            scope: ASGI connection scope
        """

    async def __call__(
        self,
        receive: ASGIReceiveCallable,
        send: ASGISendCallable,
    ) -> None:
        """
        Handle the connection.

        Args:
            receive: Callable for receiving events
            send: Callable for sending events
        """
```

### Callable Types

```python { .api }
# Callable for receiving events from the server
ASGIReceiveCallable = Callable[[], Awaitable[ASGIReceiveEvent]]

# Callable for sending events to the server
ASGISendCallable = Callable[[ASGISendEvent], Awaitable[None]]
```

## Scope Types

### ASGI Version Information

```python { .api }
class ASGIVersions(TypedDict):
    """ASGI version information included in every scope."""

    spec_version: str
    """ASGI specification version (e.g., "2.3")."""

    version: Literal["2.0"] | Literal["3.0"]
    """ASGI version ("2.0" for ASGI2, "3.0" for ASGI3)."""
```

### HTTP Scope

```python { .api }
class HTTPScope(TypedDict):
    """
    Scope for HTTP connections.

    Contains all information about an HTTP request.
    """

    type: Literal["http"]
    """Connection type (always "http" for HTTP connections)."""

    asgi: ASGIVersions
    """ASGI version information."""

    http_version: str
    """HTTP version string (e.g., "1.1", "2", "3")."""

    method: str
    """HTTP method (e.g., "GET", "POST", "PUT", "DELETE")."""

    scheme: str
    """URL scheme ("http" or "https")."""

    path: str
    """URL path, percent-decoded (e.g., "/api/users")."""

    raw_path: bytes
    """URL path as bytes, not decoded (e.g., b"/api/users")."""

    query_string: bytes
    """URL query string as bytes, without leading "?" (e.g., b"page=1&limit=10")."""

    root_path: str
    """
    Root path for the application when mounted at a subpath.
    Empty string if mounted at root. (e.g., "/api/v1" or "")
    """

    headers: Iterable[tuple[bytes, bytes]]
    """
    HTTP headers as list of (name, value) byte tuples.
    Header names are lowercase. (e.g., [(b"host", b"example.com"), (b"user-agent", b"curl/7.64.1")])
    """

    client: tuple[str, int] | None
    """
    Client address as (host, port) tuple.
    None if not available. (e.g., ("127.0.0.1", 54321))
    """

    server: tuple[str, int | None] | None
    """
    Server address as (host, port) tuple.
    Port may be None. (e.g., ("localhost", 8000))
    """

    state: NotRequired[dict[str, Any]]
    """
    Optional state dictionary for sharing data between middleware and application.
    Not set by default.
    """

    extensions: NotRequired[dict[str, dict[object, object]]]
    """
    Optional extensions dictionary for protocol-specific features.
    Not set by default.
    """
```

### WebSocket Scope

```python { .api }
class WebSocketScope(TypedDict):
    """
    Scope for WebSocket connections.

    Contains all information about a WebSocket connection.
    """

    type: Literal["websocket"]
    """Connection type (always "websocket" for WebSocket connections)."""

    asgi: ASGIVersions
    """ASGI version information."""

    http_version: str
    """HTTP version used for WebSocket handshake (e.g., "1.1")."""

    scheme: str
    """URL scheme ("ws" or "wss")."""

    path: str
    """URL path, percent-decoded (e.g., "/ws/chat")."""

    raw_path: bytes
    """URL path as bytes, not decoded (e.g., b"/ws/chat")."""

    query_string: bytes
    """URL query string as bytes, without leading "?" (e.g., b"room=general")."""

    root_path: str
    """
    Root path for the application when mounted at a subpath.
    Empty string if mounted at root.
    """

    headers: Iterable[tuple[bytes, bytes]]
    """
    HTTP headers from WebSocket handshake as list of (name, value) byte tuples.
    Header names are lowercase.
    """

    client: tuple[str, int] | None
    """
    Client address as (host, port) tuple.
    None if not available.
    """

    server: tuple[str, int | None] | None
    """
    Server address as (host, port) tuple.
    Port may be None.
    """

    subprotocols: Iterable[str]
    """
    WebSocket subprotocols requested by client in Sec-WebSocket-Protocol header.
    (e.g., ["chat", "superchat"])
    """

    state: NotRequired[dict[str, Any]]
    """
    Optional state dictionary for sharing data between middleware and application.
    """

    extensions: NotRequired[dict[str, dict[object, object]]]
    """
    Optional extensions dictionary for protocol-specific features.
    """
```

### Lifespan Scope

```python { .api }
class LifespanScope(TypedDict):
    """
    Scope for lifespan protocol.

    Used for application startup and shutdown events.
    """

    type: Literal["lifespan"]
    """Connection type (always "lifespan")."""

    asgi: ASGIVersions
    """ASGI version information."""

    state: NotRequired[dict[str, Any]]
    """
    Optional state dictionary for sharing data during application lifecycle.
    """
```

### Scope Unions

```python { .api }
# Union of HTTP and WebSocket scopes
WWWScope = Union[HTTPScope, WebSocketScope]

# Union of all scope types
Scope = Union[HTTPScope, WebSocketScope, LifespanScope]
```

## HTTP Event Types

### Request Events

```python { .api }
class HTTPRequestEvent(TypedDict):
    """
    HTTP request body chunk from server to application.
    """

    type: Literal["http.request"]
    """Event type."""

    body: bytes
    """Request body chunk (may be empty)."""

    more_body: bool
    """
    Whether more body chunks will follow.
    False indicates this is the last chunk.
    """
```

```python { .api }
class HTTPDisconnectEvent(TypedDict):
    """
    HTTP connection disconnected by client.
    """

    type: Literal["http.disconnect"]
    """Event type."""
```

### Response Events

```python { .api }
class HTTPResponseStartEvent(TypedDict):
    """
    Start HTTP response with status and headers.
    """

    type: Literal["http.response.start"]
    """Event type."""

    status: int
    """HTTP status code (e.g., 200, 404, 500)."""

    headers: NotRequired[Iterable[tuple[bytes, bytes]]]
    """
    Optional HTTP response headers as (name, value) byte tuples.
    Header names should be lowercase.
    """

    trailers: NotRequired[bool]
    """
    Optional flag indicating if HTTP trailers will be sent.
    Requires HTTP/1.1 chunked encoding or HTTP/2+.
    """
```

```python { .api }
class HTTPResponseBodyEvent(TypedDict):
    """
    HTTP response body chunk from application to server.
    """

    type: Literal["http.response.body"]
    """Event type."""

    body: bytes
    """Response body chunk (may be empty)."""

    more_body: NotRequired[bool]
    """
    Optional flag indicating more body chunks will follow.
    False or omitted indicates this is the last chunk.
    """
```

```python { .api }
class HTTPResponseTrailersEvent(TypedDict):
    """
    HTTP trailers sent after response body (HTTP/1.1 chunked or HTTP/2+).
    """

    type: Literal["http.response.trailers"]
    """Event type."""

    headers: Iterable[tuple[bytes, bytes]]
    """Trailer headers as (name, value) byte tuples."""

    more_trailers: bool
    """
    Whether more trailers will follow.
    Typically False as trailers are sent once.
    """
```

```python { .api }
class HTTPServerPushEvent(TypedDict):
    """
    HTTP/2 server push (hint to client to pre-load resource).
    """

    type: Literal["http.response.push"]
    """Event type."""

    path: str
    """URL path to push (e.g., "/static/app.js")."""

    headers: Iterable[tuple[bytes, bytes]]
    """Request headers for pushed resource."""
```

```python { .api }
class HTTPResponseDebugEvent(TypedDict):
    """
    Debug information event (protocol-specific).
    """

    type: Literal["http.response.debug"]
    """Event type."""

    info: dict[str, object]
    """Debug information dictionary."""
```

## WebSocket Event Types

### Connection Events

```python { .api }
class WebSocketConnectEvent(TypedDict):
    """
    WebSocket connection request from server to application.
    """

    type: Literal["websocket.connect"]
    """Event type."""
```

```python { .api }
class WebSocketAcceptEvent(TypedDict):
    """
    Accept WebSocket connection from application to server.
    """

    type: Literal["websocket.accept"]
    """Event type."""

    subprotocol: NotRequired[str | None]
    """
    Optional subprotocol to use (must be one requested by client).
    None or omitted means no subprotocol.
    """

    headers: NotRequired[Iterable[tuple[bytes, bytes]]]
    """
    Optional additional headers to send in handshake response.
    """
```

```python { .api }
class WebSocketDisconnectEvent(TypedDict):
    """
    WebSocket connection closed.
    """

    type: Literal["websocket.disconnect"]
    """Event type."""

    code: int
    """
    WebSocket close code.
    1000 = normal closure, 1001 = going away, etc.
    """

    reason: NotRequired[str | None]
    """
    Optional close reason string.
    """
```

```python { .api }
class WebSocketCloseEvent(TypedDict):
    """
    Close WebSocket connection from application to server.
    """

    type: Literal["websocket.close"]
    """Event type."""

    code: NotRequired[int]
    """
    Optional close code (default: 1000 for normal closure).
    """

    reason: NotRequired[str | None]
    """
    Optional close reason string.
    """
```

### Message Events

```python { .api }
# WebSocket receive event with bytes data
class _WebSocketReceiveEventBytes(TypedDict):
    type: Literal["websocket.receive"]
    bytes: bytes
    text: NotRequired[None]

# WebSocket receive event with text data
class _WebSocketReceiveEventText(TypedDict):
    type: Literal["websocket.receive"]
    bytes: NotRequired[None]
    text: str

# Union of bytes and text receive events
WebSocketReceiveEvent = Union[_WebSocketReceiveEventBytes, _WebSocketReceiveEventText]
"""
WebSocket message received from client.

Contains either bytes or text field, never both.
"""
```

```python { .api }
# WebSocket send event with bytes data
class _WebSocketSendEventBytes(TypedDict):
    type: Literal["websocket.send"]
    bytes: bytes
    text: NotRequired[None]

# WebSocket send event with text data
class _WebSocketSendEventText(TypedDict):
    type: Literal["websocket.send"]
    bytes: NotRequired[None]
    text: str

# Union of bytes and text send events
WebSocketSendEvent = Union[_WebSocketSendEventBytes, _WebSocketSendEventText]
"""
WebSocket message to send to client.

Must contain either bytes or text field, never both.
"""
```

### HTTP Response During WebSocket Handshake

```python { .api }
class WebSocketResponseStartEvent(TypedDict):
    """
    Send HTTP response during WebSocket handshake (reject connection).
    """

    type: Literal["websocket.http.response.start"]
    """Event type."""

    status: int
    """HTTP status code (typically 403 or 404 to reject)."""

    headers: Iterable[tuple[bytes, bytes]]
    """HTTP response headers."""
```

```python { .api }
class WebSocketResponseBodyEvent(TypedDict):
    """
    Send HTTP response body during WebSocket handshake.
    """

    type: Literal["websocket.http.response.body"]
    """Event type."""

    body: bytes
    """Response body chunk."""

    more_body: NotRequired[bool]
    """
    Optional flag indicating more body chunks will follow.
    """
```

## Lifespan Event Types

### Startup Events

```python { .api }
class LifespanStartupEvent(TypedDict):
    """
    Application startup event from server to application.
    """

    type: Literal["lifespan.startup"]
    """Event type."""
```

```python { .api }
class LifespanStartupCompleteEvent(TypedDict):
    """
    Application startup completed successfully.
    """

    type: Literal["lifespan.startup.complete"]
    """Event type."""
```

```python { .api }
class LifespanStartupFailedEvent(TypedDict):
    """
    Application startup failed.
    """

    type: Literal["lifespan.startup.failed"]
    """Event type."""

    message: str
    """Error message describing startup failure."""
```

### Shutdown Events

```python { .api }
class LifespanShutdownEvent(TypedDict):
    """
    Application shutdown event from server to application.
    """

    type: Literal["lifespan.shutdown"]
    """Event type."""
```

```python { .api }
class LifespanShutdownCompleteEvent(TypedDict):
    """
    Application shutdown completed successfully.
    """

    type: Literal["lifespan.shutdown.complete"]
    """Event type."""
```

```python { .api }
class LifespanShutdownFailedEvent(TypedDict):
    """
    Application shutdown failed.
    """

    type: Literal["lifespan.shutdown.failed"]
    """Event type."""

    message: str
    """Error message describing shutdown failure."""
```

## Event Unions

```python { .api }
# Union of all events that can be received from server
ASGIReceiveEvent = Union[
    HTTPRequestEvent,
    HTTPDisconnectEvent,
    WebSocketConnectEvent,
    WebSocketReceiveEvent,
    WebSocketDisconnectEvent,
    LifespanStartupEvent,
    LifespanShutdownEvent,
]

# Union of all events that can be sent to server
ASGISendEvent = Union[
    HTTPResponseStartEvent,
    HTTPResponseBodyEvent,
    HTTPResponseTrailersEvent,
    HTTPServerPushEvent,
    HTTPDisconnectEvent,
    WebSocketAcceptEvent,
    WebSocketSendEvent,
    WebSocketResponseStartEvent,
    WebSocketResponseBodyEvent,
    WebSocketCloseEvent,
    LifespanStartupCompleteEvent,
    LifespanStartupFailedEvent,
    LifespanShutdownCompleteEvent,
    LifespanShutdownFailedEvent,
]

# Union of WebSocket-specific events
WebSocketEvent = Union[
    WebSocketReceiveEvent,
    WebSocketDisconnectEvent,
    WebSocketConnectEvent,
]
```

## WSGI Types

```python { .api }
# WSGI environ dictionary
Environ = MutableMapping[str, Any]
"""
WSGI environ dictionary containing CGI-like variables.
"""

# WSGI exception info tuple
ExcInfo = tuple[type[BaseException], BaseException, Optional[types.TracebackType]]
"""
Exception info tuple for WSGI error handling.
Same format as sys.exc_info().
"""

# WSGI start_response callable
StartResponse = Callable[[str, Iterable[tuple[str, str]], Optional[ExcInfo]], None]
"""
WSGI start_response callable.

Args:
    status: HTTP status string (e.g., "200 OK")
    headers: List of (header_name, header_value) tuples
    exc_info: Optional exception info for error responses
"""

# WSGI application callable
WSGIApp = Callable[[Environ, StartResponse], Union[Iterable[bytes], BaseException]]
"""
WSGI application callable.

Args:
    environ: WSGI environ dictionary
    start_response: start_response callable

Returns:
    Iterable of body bytes or exception
"""
```

## Usage Examples

### Type-Safe ASGI3 Application

```python
from uvicorn._types import (
    Scope,
    ASGIReceiveCallable,
    ASGISendCallable,
    HTTPResponseStartEvent,
    HTTPResponseBodyEvent,
)

async def app(
    scope: Scope,
    receive: ASGIReceiveCallable,
    send: ASGISendCallable,
) -> None:
    """Type-safe ASGI3 application."""
    assert scope["type"] == "http"

    # Type-safe response start event
    start_event: HTTPResponseStartEvent = {
        "type": "http.response.start",
        "status": 200,
        "headers": [[b"content-type", b"text/plain"]],
    }
    await send(start_event)

    # Type-safe response body event
    body_event: HTTPResponseBodyEvent = {
        "type": "http.response.body",
        "body": b"Hello, World!",
    }
    await send(body_event)
```

### Type-Safe HTTP Handler

```python
from uvicorn._types import (
    HTTPScope,
    ASGIReceiveCallable,
    ASGISendCallable,
    HTTPRequestEvent,
)

async def http_handler(
    scope: HTTPScope,
    receive: ASGIReceiveCallable,
    send: ASGISendCallable,
) -> None:
    """Type-safe HTTP request handler."""

    # Receive request body
    body_parts: list[bytes] = []
    while True:
        event: HTTPRequestEvent = await receive()  # type: ignore
        if event["type"] == "http.request":
            body_parts.append(event["body"])
            if not event["more_body"]:
                break

    body = b"".join(body_parts)

    # Send response
    await send({
        "type": "http.response.start",
        "status": 200,
        "headers": [[b"content-type", b"application/json"]],
    })
    await send({
        "type": "http.response.body",
        "body": b'{"message": "success"}',
    })
```

### Type-Safe WebSocket Handler

```python
from uvicorn._types import (
    WebSocketScope,
    ASGIReceiveCallable,
    ASGISendCallable,
    WebSocketConnectEvent,
    WebSocketReceiveEvent,
)

async def websocket_handler(
    scope: WebSocketScope,
    receive: ASGIReceiveCallable,
    send: ASGISendCallable,
) -> None:
    """Type-safe WebSocket handler."""

    # Wait for connection
    event: WebSocketConnectEvent = await receive()  # type: ignore
    assert event["type"] == "websocket.connect"

    # Accept connection
    await send({
        "type": "websocket.accept",
        "subprotocol": None,
    })

    # Echo messages
    while True:
        event = await receive()
        if event["type"] == "websocket.disconnect":
            break
        elif event["type"] == "websocket.receive":
            ws_event: WebSocketReceiveEvent = event  # type: ignore
            if "text" in ws_event:
                await send({
                    "type": "websocket.send",
                    "text": ws_event["text"],
                })
            elif "bytes" in ws_event:
                await send({
                    "type": "websocket.send",
                    "bytes": ws_event["bytes"],
                })
```

### Type-Safe Lifespan Handler

```python
from uvicorn._types import (
    LifespanScope,
    ASGIReceiveCallable,
    ASGISendCallable,
    LifespanStartupEvent,
    LifespanShutdownEvent,
)

async def lifespan_handler(
    scope: LifespanScope,
    receive: ASGIReceiveCallable,
    send: ASGISendCallable,
) -> None:
    """Type-safe lifespan handler."""

    # Handle startup
    event = await receive()
    if event["type"] == "lifespan.startup":
        # Perform startup tasks
        print("Starting up...")
        await send({"type": "lifespan.startup.complete"})

    # Handle shutdown
    event = await receive()
    if event["type"] == "lifespan.shutdown":
        # Perform cleanup tasks
        print("Shutting down...")
        await send({"type": "lifespan.shutdown.complete"})
```

### Type-Safe Middleware

```python
from uvicorn._types import (
    Scope,
    ASGIReceiveCallable,
    ASGISendCallable,
    ASGI3Application,
)

class TypeSafeMiddleware:
    """Type-safe ASGI middleware."""

    def __init__(self, app: ASGI3Application) -> None:
        self.app = app

    async def __call__(
        self,
        scope: Scope,
        receive: ASGIReceiveCallable,
        send: ASGISendCallable,
    ) -> None:
        # Add custom header to HTTP responses
        if scope["type"] == "http":
            async def send_with_header(message):
                if message["type"] == "http.response.start":
                    headers = list(message.get("headers", []))
                    headers.append((b"x-custom", b"middleware"))
                    message["headers"] = headers
                await send(message)

            await self.app(scope, receive, send_with_header)
        else:
            await self.app(scope, receive, send)
```
