Flask like web framework for AWS Lambda

Overview

lambdarest logo

lambdarest

Build Status Latest Version PyPI - Downloads Python Support Examples tested with pytest-readme

Python routing mini-framework for AWS Lambda with optional JSON-schema validation.

⚠️ A user study is currently happening here, and your opinion makes the day! Thanks for participating! 😊

Features

  • lambda_handler function constructor with built-in dispatcher
  • Decorator to register functions to handle HTTP methods
  • Optional JSON-schema input validation using same decorator

Support the development ❤️

You can support the development by:

  1. Contributing code

  2. Buying the maintainer a coffee

  3. Buying some Lambdarest swag

    like this mug for example:

    lambdarest mug

External articles / tutorials

Other articles? add them here

Installation

Install the package from PyPI using pip:

$ pip install lambdarest

Getting Started

This module helps you to handle different HTTP methods in your AWS Lambda.

from lambdarest import lambda_handler

@lambda_handler.handle("get")
def my_own_get(event):
    return {"this": "will be json dumped"}

##### TEST #####

input_event = {
    "body": '{}',
    "httpMethod": "GET",
    "resource": "/"
}
result = lambda_handler(event=input_event)
assert result == {"body": '{"this": "will be json dumped"}', "statusCode": 200, "headers":{}}

Documentation

See docs for documentation and examples covering amongst:

Anormal unittest behaviour with lambda_handler singleton

Because of python unittests leaky test-cases it seems like you shall beware of this issue when using the singleton lambda_handler in a multiple test-case scenario.

Tests

This package uses Poetry to install requirements and run tests.

Use the following commands to install requirements and run test-suite:

$ poetry install
$ poetry run task test

For more info see Contributing...

Changelog

See HISTORY.md

Contributors

Thanks for contributing!

@sphaugh, @amacks, @jacksgt, @mkreg, @aphexer, @nabrosimoff, @elviejokike, @eduardomourar, @devgrok, @AlbertoTrindade, @paddie, @svdgraaf, @simongarnier, @martinbuberl, @adamelmore, @sloev

Wanna contribute?

And by the way, we have a Code Of Friendlyhood!

Comments
  • Support of resource path {placeholders} in the middle

    Support of resource path {placeholders} in the middle

    I made a resource path preparing before routing.

    The issue was found when I tried to implement lambda for working with URL /bay/{bay_id}/status. The router was not able to find a correct handler.

    I made preparing of the path before routing. Now, the resource path is being filled by path parameters before the routing, but if the parameters list is incorrect, the code still returns code 404.

    opened by nabrosimoff 12
  • Make Api Gateway custom domain work (with basepath)

    Make Api Gateway custom domain work (with basepath)

    When APIGW is setup with a custom domain. The path to the call will include the basepath (if setup). To fix this, we need to check for the resource path which will contain the actual path without the basepath.

    This fixes #31

    opened by svdgraaf 12
  • Fixed issue where using path parameters but no custom domain breaks

    Fixed issue where using path parameters but no custom domain breaks

    I just redeployed an api to api gateway without a custom domain, but with path parameters in the url. This broke the parsing. I think this was an edge cased that I missed last time.

    This change fixes this issue. It checks if both path and resource are set. If so, it checks if they are the same. If so, it uses resource, if not. It uses path, which will contain all the values for the path parameters.

    opened by svdgraaf 11
  • [Question/BUG] Query Parameters converted to float

    [Question/BUG] Query Parameters converted to float

    issue / feature request

    I Would like to understand the rationale of converting any query parameter that is a series of digits to floats. I am building an API that relies on Account ID's being based which are digits, these are needed in string form and python-lambdarest uses the float() function to convert all strings that are numeric, without the ability to override this behaviour from what i can tell.

    Is there a reason for this - HTTP is a string based protocol afaik, hence converting to float seems somewhat arbitrary and if needed something that could be done in business logic vs the underlying library which is parsing the API Gateway JSON payload.

    Thanks!

    opened by andyfase 9
  • Use workzeug for route parsing

    Use workzeug for route parsing

    TL/DR: This PR makes paths like /foo/bar/<int:id>/ work.

    I needed path parameter support for my api, I noticed that Workzeug (from Flask) solved that issue already, and here we are.

    • I added a dependency on workzeug
    • I added the mapper for mapping the function calls
    • I added a short description in the readme
    opened by svdgraaf 7
  • minimally process standard lambda (dict) responses

    minimally process standard lambda (dict) responses

    Personally, I'd prefer to be able to return a normal lambda response from my handlers and not have to introduce a library-specific output format:

    @lambda_handler.handle("get", path="/")
    def index(event: dict) -> dict:
    	return {
    		"statusCode": 302,
    		"headers": {
    			"Location": "https://example.com"
    		}
    	}
    

    This allows the library to be used solely for its routing capabilities which is desirable to those that aren't interested in any output massaging.

    opened by adamelmore 6
  • Using functools wraps on inner function

    Using functools wraps on inner function

    This fixes the same issues from PR #51 , but it also works for python 2.7.

    I run into problems when trying to document the code that contained @lambda_handler and it was not possible because the wrapper function was not marked as decorator.

    opened by eduardomourar 6
  • Options for configuring CORS and preflight requests

    Options for configuring CORS and preflight requests

    Is CORS handling within the scope of this project?

    I'd like to configure CORS when I call create_lambda_handler. Maybe it would be sufficient to add a headers kwarg for my use case?

    @sloev

    opened by furrycatherder 5
  • [BUG] multiValueHeaders not being sent back (ALB)

    [BUG] multiValueHeaders not being sent back (ALB)

    It looks like ALB needs support for multiValueHeaders as part of the return JSON for things like Content-Type, headers does not seem to be properly passed through the ALB. I added a multiValueHeader element by copying and modifying headers in the to_json and inner_lambda_handler and it seems to work as expected and the ALB properly interprets. I can submit a PR, but I cannot vouch for the quality of the code, however it does seem to work

    diff --git a/lambdarest/__init__.py b/lambdarest/__init__.py
    index d8cd80f..8079e97 100755
    --- a/lambdarest/__init__.py
    +++ b/lambdarest/__init__.py
    @@ -22,10 +22,11 @@ class Response(object):
         if no headers are specified, empty dict is returned
         """
     
    -    def __init__(self, body=None, status_code=None, headers=None):
    +    def __init__(self, body=None, status_code=None, headers=None, multiValueHeaders=None):
             self.body = body
             self.status_code = status_code
             self.headers = headers
    +        self.multiValueHeaders = multiValueHeaders
             self.status_code_description = None
             self.isBase64_encoded = False
     
    @@ -42,8 +43,12 @@ class Response(object):
                 if do_json_dumps
                 else self.body,
                 "statusCode": status_code,
    -            "headers": self.headers or {},
             }
    +        ## handle multiValueHeaders if defined, default to headers
    +        if (self.multiValueHeaders == None) :
    +            response["headers"] = self.headers or {}
    +        else:
    +            response["multiValueHeaders"] = self.multiValueHeaders
             # if body is None, remove the key
             if response.get("body") == None:
                 response.pop("body")
    @@ -235,21 +240,22 @@ def create_lambda_handler(
                                 raise ValueError("Response tuple has more than 3 items")
     
                             # Unpack the tuple, missing items will be defaulted
    -                        body, status_code, headers = response + (None,) * (
    -                            3 - response_len
    +                        body, status_code, headers, multiValueHeaders = response + (None,) * (
    +                            4 - response_len
                             )
     
                         elif isinstance(response, dict) and all(
    -                        key in ["body", "statusCode", "headers"]
    +                        key in ["body", "statusCode", "headers", "multiValueHeaders"]
                             for key in response.keys()
                         ):
                             body = response.get("body")
                             status_code = response.get("statusCode") or status_code
                             headers = response.get("headers") or headers
    +                        multiValueHeaders = response.get("multiValueHeaders") or multiValueHeaders
     
                         else:  # if response is string, int, etc.
                             body = response
    -                    response = Response(body, status_code, headers)
    +                    response = Response(body, status_code, headers, multiValueHeaders)
                     return response.to_json(
                         encoder=json_encoder,
                         application_load_balancer=application_load_balancer,
    
    
    opened by amacks 5
  • Trouble installing with pip

    Trouble installing with pip

    When running the install command "pip install lambdarest" I get an error

    ERROR: Command errored out with exit status 1: command: /backend/api_lambda/bin/python3 -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/private/var/folders/65/jpxwzrxj68xb7lp74c2_yf8hrp6vql/T/pip-install-wor4aeh7/lambdarest/setup.py'"'"'; file='"'"'/private/var/folders/65/jpxwzrxj68xb7lp74c2_yf8hrp6vql/T/pip-install-wor4aeh7/lambdarest/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(file);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, file, '"'"'exec'"'"'))' egg_info --egg-base /private/var/folders/65/jpxwzrxj68xb7lp74c2_yf8hrp6vql/T/pip-install-wor4aeh7/lambdarest/pip-egg-info cwd: /private/var/folders/65/jpxwzrxj68xb7lp74c2_yf8hrp6vql/T/pip-install-wor4aeh7/lambdarest/ Complete output (5 lines): Traceback (most recent call last): File "", line 1, in File "/private/var/folders/65/jpxwzrxj68xb7lp74c2_yf8hrp6vql/T/pip-install-wor4aeh7/lambdarest/setup.py", line 9, in history = open("HISTORY.md").read() FileNotFoundError: [Errno 2] No such file or directory: 'HISTORY.md' ---------------------------------------- ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.

    Is there an issue with the setup.py script? Is this a known issue?

    opened by zchesty 5
  • Briefly mention in README how to setup api-gateway for Lambdarest lambda

    Briefly mention in README how to setup api-gateway for Lambdarest lambda

    Hi @svdgraaf, Can you maybe briefly write an update to the readme mentioning how to setup the api-gateway for using Lambdarest. I haven't been using lambdarest in production in over a year so i am a bit rusty. Thanks for your contributions!

    help wanted 
    opened by sloev 5
  • [ENHANCEMENT] Support Lambda Function URLs

    [ENHANCEMENT] Support Lambda Function URLs

    I've been using lambdarest for years and tried the latest version with Lambda Function URLs, which will not work without a bit of work (notably, the field names in the event are slightly different than what the code expects). I recognize this project is currently unmaintained, but wanted to introduce this enhancement as a notice to other users should they consider trying this themselves.

    Sample event from Lambda Function URL request

    {
      "version": "2.0",
      "routeKey": "$default",
      "rawPath": "/my/path",
      "rawQueryString": "parameter1=value1&parameter1=value2&parameter2=value",
      "cookies": [
        "cookie1",
        "cookie2"
      ],
      "headers": {
        "header1": "value1",
        "header2": "value1,value2"
      },
      "queryStringParameters": {
        "parameter1": "value1,value2",
        "parameter2": "value"
      },
      "requestContext": {
        "accountId": "123456789012",
        "apiId": "<urlid>",
        "authentication": null,
        "authorizer": {
            "iam": {
                    "accessKey": "AKIA...",
                    "accountId": "111122223333",
                    "callerId": "AIDA...",
                    "cognitoIdentity": null,
                    "principalOrgId": null,
                    "userArn": "arn:aws:iam::111122223333:user/example-user",
                    "userId": "AIDA..."
            }
        },
        "domainName": "<url-id>.lambda-url.us-west-2.on.aws",
        "domainPrefix": "<url-id>",
        "http": {
          "method": "POST",
          "path": "/my/path",
          "protocol": "HTTP/1.1",
          "sourceIp": "123.123.123.123",
          "userAgent": "agent"
        },
        "requestId": "id",
        "routeKey": "$default",
        "stage": "$default",
        "time": "12/Mar/2020:19:03:58 +0000",
        "timeEpoch": 1583348638390
      },
      "body": "Hello from client!",
      "pathParameters": null,
      "isBase64Encoded": false,
      "stageVariables": null
    }
    
    help wanted Pay maintainer to give a damn 😅 
    opened by gswalden 1
Releases(untagged-080ed2ae2bbff1b043aa)
Owner
sloev / Johannes Valbjørn
I like to write software and then give it away for free. Walking the thin line between silly and useful.
sloev / Johannes Valbjørn
A framework that let's you compose websites in Python with ease!

Perry Perry = A framework that let's you compose websites in Python with ease! Perry works similar to Qt and Flutter, allowing you to create componen

Linkus 13 Oct 09, 2022
The lightning-fast ASGI server. ?

The lightning-fast ASGI server. Documentation: https://www.uvicorn.org Community: https://discuss.encode.io/c/uvicorn Requirements: Python 3.6+ (For P

Encode 6k Jan 03, 2023
The core of a service layer that integrates with the Pyramid Web Framework.

pyramid_services The core of a service layer that integrates with the Pyramid Web Framework. pyramid_services defines a pattern and helper methods for

Michael Merickel 78 Apr 15, 2022
O SnakeG é um WSGI feito para suprir necessidadades de perfomance e segurança.

SnakeG O SnakeG é um WSGI feito para suprir necessidadades de perfomance e segurança. Veja o que o SnakeG possui: Multiprocessamento de requisições HT

Jaedson Silva 1 Jul 02, 2022
An effective, simple, and async security library for the Sanic framework.

Sanic Security An effective, simple, and async security library for the Sanic framework. Table of Contents About the Project Getting Started Prerequis

Sunset Dev 72 Nov 30, 2022
An easy-to-use high-performance asynchronous web framework.

An easy-to-use high-performance asynchronous web framework.

Aber 264 Dec 31, 2022
Pulumi-checkly - Checkly Pulumi Provider With Python

🚨 This project is still in very early stages and is not stable, use at your own

Checkly 16 Dec 15, 2022
A python application to log QSOs directly to QRZ.com from the command line

qrzlogger This script is a QRZ.com command line QSO logger. It does the following: asks the user for a call sign displays available call sign info pul

Michael Clemens 15 Jul 16, 2021
A familiar HTTP Service Framework for Python.

Responder: a familiar HTTP Service Framework for Python Powered by Starlette. That async declaration is optional. View documentation. This gets you a

Taoufik 3.6k Dec 27, 2022
Fast⚡, simple and light💡weight ASGI micro🔬 web🌏-framework for Python🐍.

NanoASGI Asynchronous Python Web Framework NanoASGI is a fast ⚡ , simple and light 💡 weight ASGI micro 🔬 web 🌏 -framework for Python 🐍 . It is dis

Kavindu Santhusa 8 Jun 16, 2022
A Python package to easily create APIs in Python.

API_Easy An Python Package for easily create APIs in Python pip install easy-api-builder Requiremnets: = python 3.6 Required modules -- Flask Docume

Envyre-Coding 2 Jan 04, 2022
Loan qualifier app - Loan Qualifier Application Built With Python

Loan Qualifier Application This program is designed to automate the discovery pr

Phil Hills 1 Jan 04, 2022
Sanic integration with Webargs

webargs-sanic Sanic integration with Webargs. Parsing and validating request arguments: headers, arguments, cookies, files, json, etc. IMPORTANT: From

Endurant Devs 13 Aug 31, 2022
🔥 Fire up your API with this flamethrower

🔥 Fire up your API. Documentation: https://flama.perdy.io Flama Flama aims to bring a layer on top of Starlette to provide an easy to learn and fast

José Antonio Perdiguero 216 Dec 26, 2022
A minimal, extensible, fast and productive API framework for Python 3.

molten A minimal, extensible, fast and productive API framework for Python 3. Changelog: https://moltenframework.com/changelog.html Community: https:/

Bogdan Popa 980 Nov 28, 2022
Djask is a web framework for python which stands on the top of Flask and will be as powerful as Django.

Djask is a web framework for python which stands on the top of Flask and will be as powerful as Django.

Andy Zhou 27 Sep 08, 2022
Dazzler is a Python async UI/Web framework built with aiohttp and react.

Dazzler is a Python async UI/Web framework built with aiohttp and react. Create dazzling fast pages with a layout of Python components and bindings to update from the backend.

Philippe Duval 17 Oct 18, 2022
Light, Flexible and Extensible ASGI API framework

Starlite Starlite is a light, opinionated and flexible ASGI API framework built on top of pydantic and Starlette. Check out the Starlite documentation

Na'aman Hirschfeld 1.6k Jan 09, 2023
Async Python 3.6+ web server/framework | Build fast. Run fast.

Sanic | Build fast. Run fast. Build Docs Package Support Stats Sanic is a Python 3.6+ web server and web framework that's written to go fast. It allow

Sanic Community Organization 16.7k Dec 28, 2022
Microservice example with Python, Faust-Streaming and Kafka (Redpanda)

Microservices Orchestration with Python, Faust-Streaming and Kafka (Redpanda) Example project for PythonBenin meetup. It demonstrates how to use Faust

Lé 3 Jun 13, 2022