Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 24 additions & 24 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,28 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.6', '3.7', '3.8', '3.9', '3.10']
python-version: ["3.7", "3.8", "3.9", "3.10"]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- uses: actions/cache@v2
name: Configure pip caching
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
run: |
pip install -U -r requirements.txt
- name: Run tests
run: |
scripts/test
- name: Run linters
run: |
scripts/lint
- name: Run codecov
run: codecov
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- uses: actions/cache@v2
name: Configure pip caching
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
run: |
pip install -U -r requirements.txt
- name: Run tests
run: |
scripts/test
- name: Run linters
run: |
scripts/lint
- name: Run codecov
run: codecov
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
</a>
<img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/mangum.svg?style=flat-square">

Mangum is an adapter for using [ASGI](https://asgi.readthedocs.io/en/latest/) applications with AWS Lambda & API Gateway. It is intended to provide an easy-to-use, configurable wrapper for any ASGI application deployed in an AWS Lambda function to handle API Gateway requests and responses.
Mangum is an adapter for running [ASGI](https://asgi.readthedocs.io/en/latest/) applications in AWS Lambda to handle API Gateway, ALB, and Lambda@Edge events.

***Documentation***: https://mangum.io/

## Features

- API Gateway support for [HTTP](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api.html) and [REST](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-rest-api.html) APIs.
- Event handlers for API Gateway [HTTP](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api.html) and [REST](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-rest-api.html) APIs, [Application Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html), and [CloudFront Lambda@Edge](https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html).

- Compatibility with ASGI application frameworks, such as [Starlette](https://www.starlette.io/), [FastAPI](https://fastapi.tiangolo.com/), and [Quart](https://pgjones.gitlab.io/quart/).

Expand All @@ -26,7 +26,7 @@ Mangum is an adapter for using [ASGI](https://asgi.readthedocs.io/en/latest/) ap

## Requirements

Python 3.6+
Python 3.7+

## Installation

Expand All @@ -53,7 +53,7 @@ async def app(scope, receive, send):
handler = Mangum(app)
```

Or using a framework.
Or using a framework:

```python
from fastapi import FastAPI
Expand Down
2 changes: 1 addition & 1 deletion docs/asgi-frameworks.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ None of the framework details are important here. The routing decorator, request

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

Expand Down
8 changes: 4 additions & 4 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
</a>
<img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/mangum.svg?style=flat-square">

Mangum is an adapter for using [ASGI](https://asgi.readthedocs.io/en/latest/) applications with AWS Lambda & API Gateway. It is intended to provide an easy-to-use, configurable wrapper for any ASGI application deployed in an AWS Lambda function to handle API Gateway requests and responses.
Mangum is an adapter for running [ASGI](https://asgi.readthedocs.io/en/latest/) applications in AWS Lambda to handle API Gateway, ALB, and Lambda@Edge events.

***Documentation***: https://mangum.io/

## Features

- API Gateway support for [HTTP](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api.html) and [REST](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-rest-api.html) APIs.
- Event handlers for API Gateway [HTTP](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api.html) and [REST](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-rest-api.html) APIs, [Application Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html), and [CloudFront Lambda@Edge](https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html).

- Compatibility with ASGI application frameworks, such as [Starlette](https://www.starlette.io/), [FastAPI](https://fastapi.tiangolo.com/), and [Quart](https://pgjones.gitlab.io/quart/).

Expand All @@ -26,7 +26,7 @@ Mangum is an adapter for using [ASGI](https://asgi.readthedocs.io/en/latest/) ap

## Requirements

Python 3.6+
Python 3.7+

## Installation

Expand All @@ -53,7 +53,7 @@ async def app(scope, receive, send):
handler = Mangum(app)
```

Or using a framework.
Or using a framework:

```python
from fastapi import FastAPI
Expand Down
5 changes: 2 additions & 3 deletions mangum/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from .types import Request, Response
from .adapter import Mangum # noqa: F401
from mangum.adapter import Mangum

__all__ = ["Mangum", "Request", "Response"]
__all__ = ["Mangum"]
104 changes: 65 additions & 39 deletions mangum/adapter.py
Original file line number Diff line number Diff line change
@@ -1,66 +1,92 @@
from itertools import chain
import logging
from contextlib import ExitStack
from typing import List, Optional, Type
import warnings


from mangum.exceptions import ConfigurationError
from mangum.handlers.abstract_handler import AbstractHandler
from mangum.protocols import HTTPCycle, LifespanCycle
from mangum.types import ASGIApp, LambdaEvent, LambdaContext
from mangum.handlers import ALB, HTTPGateway, APIGateway, LambdaAtEdge
from mangum.exceptions import ConfigurationError
from mangum.types import (
ASGIApp,
LifespanMode,
LambdaConfig,
LambdaEvent,
LambdaContext,
LambdaHandler,
)


DEFAULT_TEXT_MIME_TYPES = [
"text/",
"application/json",
"application/javascript",
"application/xml",
"application/vnd.api+json",
]
logger = logging.getLogger("mangum")


logger = logging.getLogger("mangum")
HANDLERS: List[Type[LambdaHandler]] = [
ALB,
HTTPGateway,
APIGateway,
LambdaAtEdge,
]


class Mangum:
"""
Creates an adapter instance.

* **app** - An asynchronous callable that conforms to version 3.0 of the ASGI
specification. This will usually be an ASGI framework application instance.
* **lifespan** - A string to configure lifespan support. Choices are `auto`, `on`,
and `off`. Default is `auto`.
* **text_mime_types** - A list of MIME types to include with the defaults that
should not return a binary response in API Gateway.
* **api_gateway_base_path** - A string specifying the part of the url path after
which the server routing begins.
"""

def __init__(
self,
app: ASGIApp,
lifespan: str = "auto",
lifespan: LifespanMode = "auto",
api_gateway_base_path: str = "/",
custom_handlers: Optional[List[Type[LambdaHandler]]] = None,
) -> None:
if lifespan not in ("auto", "on", "off"):
raise ConfigurationError(
"Invalid argument supplied for `lifespan`. Choices are: auto|on|off"
)

self.app = app
self.lifespan = lifespan
self.api_gateway_base_path = api_gateway_base_path
self.api_gateway_base_path = api_gateway_base_path or "/"
self.config = LambdaConfig(api_gateway_base_path=self.api_gateway_base_path)

if self.lifespan not in ("auto", "on", "off"):
raise ConfigurationError(
"Invalid argument supplied for `lifespan`. Choices are: auto|on|off"
if custom_handlers is not None:
warnings.warn( # pragma: no cover
"Support for custom event handlers is currently provisional and may "
"drastically change (or be removed entirely) in the future.",
FutureWarning,
)

def __call__(self, event: LambdaEvent, context: LambdaContext) -> dict:
logger.debug("Event received.")
self.custom_handlers = custom_handlers or []

def infer(self, event: LambdaEvent, context: LambdaContext) -> LambdaHandler:
for handler_cls in chain(
self.custom_handlers,
HANDLERS,
):
handler = handler_cls.infer(
event,
context,
self.config,
)
if handler:
break
else:
raise RuntimeError( # pragma: no cover
"The adapter was unable to infer a handler to use for the event. This "
"is likely related to how the Lambda function was invoked. (Are you "
"testing locally? Make sure the request payload is valid for a "
"supported handler.)"
)

return handler

def __call__(self, event: LambdaEvent, context: LambdaContext) -> dict:
handler = self.infer(event, context)
with ExitStack() as stack:
if self.lifespan != "off":
if self.lifespan in ("auto", "on"):
lifespan_cycle = LifespanCycle(self.app, self.lifespan)
stack.enter_context(lifespan_cycle)

handler = AbstractHandler.from_trigger(
event, context, self.api_gateway_base_path
)
http_cycle = HTTPCycle(handler.request)
response = http_cycle(self.app, handler.body)
http_cycle = HTTPCycle(handler.scope, handler.body)
http_response = http_cycle(self.app)

return handler(http_response)

return handler.transform_response(response)
assert False, "unreachable" # pragma: no cover
6 changes: 6 additions & 0 deletions mangum/handlers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from mangum.handlers.api_gateway import APIGateway, HTTPGateway
from mangum.handlers.alb import ALB
from mangum.handlers.lambda_at_edge import LambdaAtEdge


__all__ = ["APIGateway", "HTTPGateway", "ALB", "LambdaAtEdge"]
Loading