Skip to content

Frameworks

Mangum is intended to provide support to any ASGI (Asynchronous Server Gateway Interface) application or framework. The "turtles all the way down" principle of ASGI allows for a great deal of interoperability across many different implementations, so the adapter should "just work"* for any ASGI application or framework.

* if it doesn't, then please open an issue. :)

Background

We can think about the ASGI framework support without referencing an existing implementation. There are no framework-specific rules or dependencies in the adapter class, and all applications will be treated the same.

Let's invent an API for a non-existent microframework to demonstrate things further. This could represent any ASGI framework application:

import mangum.adapter
import framework
from mangum import Mangum

app = framework.applications.Application()


@app.route("/")
def endpoint(request: framework.requests.Request) -> dict:
    return {"hi": "there"}


handler = Mangum(app)

None of the framework details are important here. The routing decorator, request parameter, and return value of the endpoint method could be anything. The app instance will be a valid app parameter for Mangum so long as the framework exposes an ASGI-compatible interface:

class Application(Protocol):
    async def __call__(self, scope: Scope, receive: ASGIReceive, send: ASGISend) -> None:
        ...

Limitations

An application or framework may implement behaviour that is incompatible with the limitations of AWS Lambda, and there may be additional configuration required depending on a particular deployment circumstance. In some cases it is possible to work around these limitations, but these kinds of limitations should generally be dealt with outside of Mangum itself.

Frameworks

The examples on this page attempt to demonstrate a basic implementation of a particular framework (usually from official documentation) to highlight the interaction with Mangum. Specific deployment tooling, infrastructure, external dependencies, etc. are not taken into account.

Starlette

Starlette is a lightweight ASGI framework/toolkit, which is ideal for building high performance asyncio services.

Mangum uses it as a toolkit in tests. It is developed by Encode, a wonderful community and collection of projects that are forming the foundations of the Python async web ecosystem.

Define an application:

from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
from mangum import Mangum


async def homepage(request):
    return JSONResponse({'hello': 'world'})

routes = [
    Route("/", endpoint=homepage)
]

app = Starlette(debug=True, routes=routes)

Then wrap it using Mangum:

handler = Mangum(app)

FastAPI

FastAPI is a modern, fast (high-performance), web framework for building APIs with Python based on standard Python type hints.

from fastapi import FastAPI
from mangum import Mangum

app = FastAPI()


@app.get("/")
def read_root():
    return {"Hello": "World"}


@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
    return {"item_id": item_id, "q": q}

handler = Mangum(app)

Responder

Responder is a familiar HTTP Service Framework for Python, powered by Starlette. The static_dir and templates_dir parameters must be set to none to disable Responder's automatic directory creation behaviour because AWS Lambda is a read-only file system - see the limitations section for more details.

from mangum import Mangum
import responder

app = responder.API(static_dir=None, templates_dir=None)


@app.route("/{greeting}")
async def greet_world(req, resp, *, greeting):
    resp.text = f"{greeting}, world!"


handler = Mangum(app)

The adapter usage for both FastAPI and Responder is the same as Starlette. However, this may be expected because they are built on Starlette - what about other frameworks?

Quart

Quart is a Python ASGI web microframework. It is intended to provide the easiest way to use asyncio functionality in a web context, especially with existing Flask apps. This is possible as the Quart API is a superset of the Flask API.

from quart import Quart
from mangum import Mangum

app = Quart(__name__)


@app.route("/hello")
async def hello():
    return "hello world!"

handler = Mangum(app)

Sanic

Sanic is a Python web server and web framework that's written to go fast. It allows the usage of the async/await syntax added in Python 3.5, which makes your code non-blocking and speedy.

from sanic import Sanic
from sanic.response import json
from mangum import Mangum

app = Sanic()


@app.route("/")
async def test(request):
    return json({"hello": "world"})


handler = Mangum(app)

Django

Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design.

It started introducing ASGI support in version 3.0. Certain async capabilities are not yet implemented and planned for future releases, however it can still be used with Mangum and other ASGI applications at the outer application level.

# asgi.py
import os
from mangum import Mangum
from django.core.asgi import get_asgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")

application = get_asgi_application()

handler = Mangum(application, lifespan="off")

This example looks a bit different than the others because it is based on Django's standard project configuration, but the ASGI behaviour is the same.

Channels

Channels is a project that takes Django and extends its abilities beyond HTTP - to handle WebSockets, chat protocols, IoT protocols, and more. It is the original driving force behind the ASGI specification.

It currently does not support ASGI version 3, but you can convert the application from ASGI version 2 using the guarantee_single_callable method provided in asgiref.

# asgi.py
import os
import django
from channels.routing import get_default_application
from asgiref.compatibility import guarantee_single_callable
from mangum import Mangum


os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")
django.setup()
application = get_default_application()

wrapped_application = guarantee_single_callable(application)
handler = Mangum(wrapped_application, lifespan="off")