Skip to main content

WebSocket support for Mangum (AWS API Gateway WebSocket API → FastAPI)

Project description

mangum-ws

WebSocket support for Mangum — use FastAPI WebSockets on AWS Lambda behind API Gateway WebSocket API.

Try it now — a working chat demo:

git clone https://github.com/okigan/mangum-ws.git && cd mangum-ws
uv sync --group dev
uv run python examples/demochat.py
# Open http://localhost:8000 in two browser tabs

Problem

Mangum lets you run ASGI apps (like FastAPI) on AWS Lambda behind API Gateway. It handles HTTP requests well, but API Gateway WebSocket API works differently: there's no persistent server — each WebSocket event ($connect, $disconnect, messages) triggers a separate Lambda invocation, and sending messages back requires calling the API Gateway Management API via HTTP.

Mangum doesn't natively support this. mangum-ws bridges the gap with a single MangumWS object:

  • Inbound (Lambda): converts API Gateway WebSocket events into FastAPI route calls via a Mangum custom handler
  • Outbound (Lambda): sends messages back to clients via boto3 post_to_connection
  • Local dev: mounts a real FastAPI WebSocket endpoint so the same code works without AWS

Install

uv add mangum-ws
# With AWS support (boto3):
uv add "mangum-ws[aws]"

For local development with ws.mount(), uvicorn needs a WebSocket library:

uv add "uvicorn[standard]"

Quick Start

import os
from fastapi import FastAPI
from mangum import Mangum
from mangum_ws import MangumWS

app = FastAPI()

# One object, auto-selects AWS or local based on endpoint URL
ws = MangumWS(endpoint_url=os.getenv("APIGW_MANAGEMENT_URL"))

# Register WebSocket lifecycle handlers (write once, used everywhere)
@ws.on_connect
async def handle_connect(connection_id: str):
    print(f"Connected: {connection_id}")

@ws.on_disconnect
async def handle_disconnect(connection_id: str):
    print(f"Disconnected: {connection_id}")

@ws.on_message
async def handle_message(connection_id: str, data: dict):
    # Subscribe this connection to a topic, etc.
    pass

# Standard FastAPI: include the router (generates /internal/websocket/* routes)
app.include_router(ws.router)

# Local dev: mount a real WebSocket endpoint (no-op in production)
ws.mount(app)

# Sending messages back to clients
async def notify(connection_ids: set[str], payload: dict):
    gone = await ws.send(connection_ids=connection_ids, data=payload)
    # Remove gone connection IDs from your subscription store
    return gone

# Lambda handler
handler = Mangum(app, custom_handlers=[ws.handler])

How It Works

In production, API Gateway WebSocket API manages connections and invokes Lambda for each event ($connect, $disconnect, sendmessage). The library converts these into FastAPI route calls via a Mangum custom handler, and sends messages back via boto3.

For local development, ws.mount() creates a real @app.websocket() endpoint that reuses the same handlers — so your code works identically in both environments.

API

MangumWS(endpoint_url=None)

Main entry point. Uses AwsGateway (boto3) if endpoint_url is provided, LocalGateway (in-memory) otherwise.

@ws.on_connect / @ws.on_disconnect / @ws.on_message

Decorators to register WebSocket lifecycle handlers. Each handler is written once and used in both Lambda (ws.router) and local dev (ws.mount):

  • @ws.on_connectasync def(connection_id: str) -> None — called on $connect
  • @ws.on_disconnectasync def(connection_id: str) -> None — called on $disconnect
  • @ws.on_messageasync def(connection_id: str, data: dict) -> None — called on custom routes (e.g. sendmessage)

All are optional.

ws.router

A fastapi.APIRouter containing POST /internal/websocket/{connect,disconnect,sendmessage}/{connection_id} routes that dispatch to your registered handlers. Add with app.include_router(ws.router).

ws.mount(app, path="/")

Mount a real @app.websocket() endpoint for local development, reusing the registered handlers. No-op in production (so you can call it unconditionally).

ws.handler

The Mangum custom handler class. Pass to Mangum(app, custom_handlers=[ws.handler]).

ws.send(connection_ids, data) -> set[str]

Send data (dict or string) to all connection_ids. Returns the set of gone (disconnected) connection IDs.

ws.send_to_connection(connection_id, data) -> bool

Send to a single connection. Returns False if the connection is gone.

ws.is_local

True when backed by LocalGateway (local dev), False when backed by AwsGateway.

License

MIT


Star History Chart

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mangum_ws-0.1.2.tar.gz (61.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mangum_ws-0.1.2-py3-none-any.whl (9.4 kB view details)

Uploaded Python 3

File details

Details for the file mangum_ws-0.1.2.tar.gz.

File metadata

  • Download URL: mangum_ws-0.1.2.tar.gz
  • Upload date:
  • Size: 61.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for mangum_ws-0.1.2.tar.gz
Algorithm Hash digest
SHA256 b8d4a41438a5dcf73bb98ffec8498e862d39502b83551c083855ffd493534bc9
MD5 a09cf392d40a86818aa5342ac4a109ef
BLAKE2b-256 183fb11889e143f743064f6291f110b1b8f12aa24d0cf8c25bac3f919e08280d

See more details on using hashes here.

File details

Details for the file mangum_ws-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: mangum_ws-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 9.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for mangum_ws-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 6ce3804eaf56741b3d9552661ab2e170a1291e488b1850d8ba2b89e66254ce89
MD5 43ea0e5b68ae9d332d4769ebdd81005e
BLAKE2b-256 15fbd70dee0b75d2c307093bf7d3f5ef8f7a6724f14ab8388b6f440330974d0d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page