Coder Social home page Coder Social logo

jordaneremieff / mangum Goto Github PK

View Code? Open in Web Editor NEW
1.6K 15.0 99.0 3.71 MB

AWS Lambda support for ASGI applications

Home Page: https://mangum.io/

License: MIT License

Python 99.63% Shell 0.37%
asgi aws lambda serverless python asyncio api-gateway starlette fastapi quart

mangum's Introduction

Mangum

Package version Build Status

PyPI - Python Version

Mangum is an adapter for running ASGI applications in AWS Lambda to handle Function URL, API Gateway, ALB, and Lambda@Edge events.

Documentation: https://mangum.io/

Features

Requirements

Python 3.7+

Installation

pip install mangum

Example

from mangum import Mangum

async def app(scope, receive, send):
    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"Hello, world!"})


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

Or using a framework:

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, lifespan="off")

mangum's People

Contributors

a-feld avatar allan-simon avatar aminalaee avatar araki-yzrh avatar bradsbrown avatar dspatoulas avatar ediskandarov avatar eduardovra avatar feriixu avatar four43 avatar fullonic avatar georgebv avatar ilyasukhanov avatar jordaneremieff avatar jurasofish avatar khamaileon avatar koxudaxi avatar kylebarron avatar lsorber avatar minamijoyo avatar nathanglover avatar relsunkaev avatar remorses avatar simonw avatar skalt avatar whynothugo avatar xpayn avatar zachmullen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mangum's Issues

Zappa + Starlette

Anyone tried using Zappa to deploy Starlette with Mangum?

I can't figure it out how to do it, or it is even possible to do it

How to use ASGI adapter - mangum?

I need to move from Flask to Quart to handle async. Quart has mangum as recommended ASGI adapter.

I am trying to run a test to get some idea what this is all about but I when run the example, the script get executed and there is no return (the same if I run example from quart https://pgjones.gitlab.io/quart/deployment.html)

app_test.py:

from mangum import Mangum

async def app(scope, receive, send):
    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"Hello, world!"})
handler = Mangum(app)

api$ python app_test.py
api$

I'm running Python 3.7.3 (default, Mar 27 2019, 22:11:17)

How can I test your example? Thanks.

More code examples

So the examples so far have been relatively basic "Hello World" applications, it would be good to test this against some more complex examples in order to shake out any further fixes/additions to the implementation.

Pass mypy checks

As of yet, ./scripts/test doesn't run mypy. A quick check shows 18 type errors.

AWS Lambda specific CLI tooling/boilerplate

Somewhat related to #5, but rather than a step-by-step guide it may make sense to include CLI/configuration tools/boilerplate specifically for AWS Lambda.

Going to try and figure something out for this while I investigate #7 and give AWS a bit more focus now.

How to connect with Django app?

Hi there,

I'm trying to get a better idea of what using Mangum usage looks like with a Django application. I've looked at the example, but don't really understand how that translates to pointing to a Django application.

More specifically, what does app in

handler = Mangum(app, enable_lifespan=False)

refer to when pointing to a full Django application?

Handle Exception on mangum

Thank you for creating great library!!

I found the not good behavior when calling exception_handler with Exception on FastAPI

I defined exception_hanlder for Exception which returns JSONResponse.

@app.exception_handler(Exception)
def all_exception_handler(_: Any, error: Exception):
    return JSONResponse(status_code=500, content={"message": error.args, "code": 500})

I want to get a response on which status code is 500 with content.
FastAPI(Starrett) raises Exception.
Mangum doesn't handle the exception and lambda was die. I can't get an excepted response from APIGateway.

However, Uvicorn handles the exception and returns expected response.

Could you change Mangum to return excepted response?
If you need the PR then, I can do it.

Thank you.

Trio support

So I admittedly don't know how much may be involved here, but my initial thoughts are that including support for ASGI applications using Trio wouldn't require too much to implement as an adapter here.

Remove the AWS CLI

So initially this project started out as only an AWS solution, but since then has shifted towards general FaaS support. The AWS CLI was something that I really wanted to include to simplify an otherwise tedious deployment process, but I'm beginning to think including it here is more trouble than it's worth - I'd rather focus on the adapters.

I think I will ultimately remove it.

Reconsidering multiple platform support

So initially I set out to implement an adapter for AWS Lambda / API Gateway, but then I was curious and started experimenting with Azure Functions. This led to shifting focus to multiple platform support, but after getting to this point, I'm wondering if this should be reconsidered because:

  • Nearly all cases where I've seen interest in serverless ASGI has been for AWS Lambda specifically.

  • It may be better to provide great support for a single platform that has widespread use vs. OK support for multiple platforms that don't get used much.

  • WebSocket support in AWS is definitely something platform-specific I want to focus on.

  • Creating deployment examples is much easier when considering one platform and perhaps I can eventually get some decent tooling to make that process as simple as possible here.

If there isn't any strong support to include other platforms, then I think I may re-focus back on solely the AWS case and pull the Azure Functions support into a different project.

Does anyone thoughts on this?

Split CLI out into separate package

Since the CLI is experimental and doesn't need to be included in deployments it probably would make sense to create a different project for configuring deployments specifically.

Deployment & configuration instructions

Will lean on the official docs of the platforms used for the most part, but some step-by-step instructions on setting up on AWS Lambda or Azure with ASGI would be worth including.

Issue with Serverless offline plugin

from mangum import Mangum
from fastapi import FastAPI


app = FastAPI()


@app.post("/items/")
def create_item(item_id: int):
    return {"id": item_id}


@app.get("/items/")
def list_items():
    items = [{"id": i} for i in range(10)]
    return items


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


handler = Mangum(app)

I'm using the above code when specified in main.py and it's configured with a catch-all route in serverless.yml. I want to test it locally using the serverless-offline plugin but when I run the offline plugin using sls offline, I don't get any response in the browser for any routes. It just says, localhost didnโ€™t send any data.

What could I be doing wrong? The offline plugin is listening on port 3000 by default.

Error when no headers in request to API gateway

I've got a normal setup, based closely on the example in magnum-cli and terraform docs on AWS lambda. Using the AWS api gateway test button throws this error:

# loosely translated from the API gateway log
Endpoint response body before transformations:
  errorMessage:
    message: 'NoneType' object has no attribute 'get'
    errorType: AttributeError
    stackTrace: >
      File "/var/task/mangum/adapter.py", line 40, in __call__
        raise exc
      File "/var/task/mangum/adapter.py", line 35, in __call__
        response = self.handler(event, context)
      File "/var/task/mangum/adapter.py", line 50, in handler
        response = handle_http(self.app, event, context)
      File "/var/task/mangum/protocols/http.py", line 58, in handle_http
        server, client = get_server_and_client(event)
      File "/var/task/mangum/utils.py", line 22, in get_server_and_client
        server_addr = event["headers"].get("Host", None)

Adding Accept:application/json to the textbox for headers resolves the issue, and I get my expected { greeting: "hello" } JSON back.

Retrieve lambda event object on FastAPI

I use mangum with FastAPI.
Also, I often create an app which authenticates the request by Cognito

I want to obtain a few Cognito information(eg: cognitoIdentityPoolId ) from lambda event because I must use the information for business logic on API.
(https://docs.aws.amazon.com/lambda/latest/dg/with-on-demand-https.html)

Unfortunately, Mangum doesn't pass the raw lambda event object to a function(controller).
Is there a way to retrieve an event object of lambda?
Or, Could you please implement it?
Btw, I don't know how to pass it to a function ๐Ÿ˜•

Storage backend

It would be useful to have a configurable storage backend for serving staticfiles and assets. I began implementing something using S3 to use specifically here, but I'm not certain if it might be better as a generic ASGI storage backend in a separate project.

I'll probably do a first pass for S3/AWS/Mangum first, then potentially pull it out.

Deploying FastAPI as Lambda Function

from fastapi import FastAPI
from mangum import Mangum

app = FastAPI()

@app.get("/")
def hello_world():
    return {"hello": "world"}

handler = Mangum(app)

ERROR:

[ERROR] TypeError: __call__() takes 2 positional arguments but 4 were given
Traceback (most recent call last):
  File "/var/task/mangum/__init__.py", line 123, in __call__
    raise exc
  File "/var/task/mangum/__init__.py", line 118, in __call__
    response = self.asgi(*args, **kwargs)
  File "/var/task/mangum/__init__.py", line 178, in asgi
    response = asgi_cycle(self.app, body=body)
  File "/var/task/mangum/__init__.py", line 38, in __call__
    asgi_instance = app(self.scope, self.receive, self.send)

I tried this, but could not import AWSLambdaAdapter

from mangum.platforms.aws.adapter import AWSLambdaAdapter

Can you please provide a working example of this?

FastAPI support

Using the following application code:

from mangum.platforms.aws.adapter import AWSLambdaAdapter
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def read_root():
    return {"hello": "world"}


handler = AWSLambdaAdapter(app)

I ran into this error after deploying to AWS:

[ERROR] AttributeError: module 'typing' has no attribute '_ClassVar'
Traceback (most recent call last):
  File "/var/lang/lib/python3.7/imp.py", line 234, in load_module
    return load_source(name, filename, file)
  File "/var/lang/lib/python3.7/imp.py", line 171, in load_source
    module = _load(spec)
  File "<frozen importlib._bootstrap>", line 696, in _load
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/var/task/asgi.py", line 19, in <module>
    from fastapi import FastAPI
  File "/var/task/fastapi/__init__.py", line 5, in <module>
    from .applications import FastAPI
  File "/var/task/fastapi/applications.py", line 3, in <module>
    from fastapi import routing
  File "/var/task/fastapi/routing.py", line 6, in <module>
    from fastapi import params
  File "/var/task/fastapi/params.py", line 4, in <module>
    from pydantic import Schema
  File "/var/task/pydantic/__init__.py", line 2, in <module>
    from .class_validators import validator
  File "/var/task/pydantic/class_validators.py", line 19, in <module>
    @dataclass
  File "/var/task/dataclasses.py", line 958, in dataclass
    return wrap(_cls)
  File "/var/task/dataclasses.py", line 950, in wrap
    return _process_class(cls, init, repr, eq, order, unsafe_hash, frozen)
  File "/var/task/dataclasses.py", line 801, in _process_class
    for name, type in cls_annotations.items()]
  File "/var/task/dataclasses.py", line 801, in <listcomp>
    for name, type in cls_annotations.items()]
  File "/var/task/dataclasses.py", line 659, in _get_field
    if (_is_classvar(a_type, typing)
  File "/var/task/dataclasses.py", line 550, in _is_classvar
    return type(a_type) is typing._ClassVar

Connection scope definition

There are a few things missing from each adapter in regards to a complete scope, ie: optional values like server and client in the Azure Functions adapter. Additionally, the server and client being parsed in the AWS Lambda adapter should be double-checked to ensure there isn't some API Gateway behaviour that is being misunderstood.

AWS tools & utilities, CLI or otherwise

Not sure the scope of what I want to include here, but I definitely think there is room for some CLI tools and utilities now that the project is focused solely on AWS.

To start I'm thinking something around static file support would be a good start. Beyond that, a deployment tool that doesn't rely on the AWS CLI.

Drop 3.6 support

I don't think this project should need to support 3.6 since AWS Lambda supports 3.7. I would have started from this perspective, but initially I included the Azure Functions adapter which only supported 3.6.

Example project for AWS

Need to create a full example project to link to for AWS at some point, potentially including how to use with other services and more advanced configurations.

Include in third-party docs

Since this is for use with any ASGI application/framework it would be a good idea to include it in projects that document third-party ASGI packages.

Handle non root base path of API Gateway custom domain

Hi

It fails to map a path correctly if an API is deployed to non root base path (eg /api) of API Gateway custom domain. serverless-wsgi handles it with an environment variable named API_GATEWAY_BASE_PATH - https://github.com/logandk/serverless-wsgi#custom-domain-names. (source - https://github.com/logandk/serverless-wsgi/blob/master/serverless_wsgi.py#L112).

It'll be helpful if the class is updated something similar shown below.

@dataclass
class Mangum:

    app: ASGIApp
    enable_lifespan: bool = True
    api_gateway_base_path: str = None
    log_level: str = "info"

...

    def strip_base_path(self, event: dict):
        path_info = event["path"]
        if self.api_gateway_base_path:
            script_name = "/" + self.api_gateway_base_path
            if path_info.startswith(script_name):
                path_info = path_info[len(script_name) :]
        return urllib.parse.unquote(path_info or "/")

    ....

    def handle_http(self, event: dict, context: dict) -> dict:
        ...
        scope = {
            ...
            "path": self.strip_base_path(event),
            ...
        }
    ...

Thanks.

Leave the "experimental/unstable" stage

Currently I have "experimental" and "unstable" littered throughout the README and documentation, mainly because I want to more thoroughly test the adapters as well as settle on a project structure/API.

I think at this point the project structure is generally going to remain the same, I wanted to keep it flexible (ie: not constraint the tooling to adapters) so I introduced mangum.platforms.* to house functionality by platform.

I think the testing related to #7 will be how I validate this, then I'll probably start presenting this as more stable in terms of adapter usage (with the AWS CLI stuff probably being an experimental feature still).

Support additional FaaS platforms

After playing around with Azure Functions in an example here, the behaviour of the ASGI adapters is generic enough that it could be rolled into this project somehow.

A few things to note:

  • Python / Linux support is currently in preview
  • Only supports Python 3.6

Generic ServerlessMiddleware

Currently there is only the AWSLambdaMiddleware used with the run_asgi method, but we'll want this for other platforms. Also considering dropping the run_asgi as a standalone method and instead implementing the run functionality in the middlewares.

Handle AWS WebSocket connection and state

The AWS WebSocket connect event contains the information required to build the connection scope, however the function response needs to be returned immediately in order to begin using connections.

Unless another solution presents itself, I'm thinking the initial connection event information will need to be persisted through DynamoDB, but there are still some challenges with how to allow the application to negotiate the connection and how to manage the ASGI cycle state generally.

https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-overview.html

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.