Skip to content
Open
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
14 changes: 9 additions & 5 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,26 @@ Installation
Usage
-----

This module works pretty much just like Flask. This allows you to run and develop this applicaiton locally just like you would in Flask. When ready deploy to Lambda, and configure the handler as::
This module works pretty much just like Flask. This allows you to run and develop this application locally just like you would in Flask. When ready deploy to Lambda, and configure the handler as::

my_python_file.app

1) Keep in mind to set up correctly lambda handler:
In this case handler: my_python_file.app
This options is available under Runtime settings -> handler

Here is an example of what ``my_python_file.py`` would look like::

from flask_lambda import FlaskLambda
from flask_lambda_rest import FlaskLambdaRest # or FlaskLambdaHttp

app = FlaskLambda(__name__)
app = FlaskLambdaRest(__name__) # FlaskLambdaHttp


@app.route('/foo', methods=['GET', 'POST'])
def foo():
data = {
'form': request.form.copy(),
'args': request.args.copy(),
'json': request.json
'args': request.args.copy()
}
return (
json.dumps(data, indent=4, sort_keys=True),
Expand All @@ -41,6 +44,7 @@ Here is an example of what ``my_python_file.py`` would look like::
if __name__ == '__main__':
app.run(debug=True)

2) Code above should work if you configure REST Api Gateway -> for HTTP Api Gateway use FlaskLambdaHttp class
Flask-RESTful
-------------

Expand Down
23 changes: 23 additions & 0 deletions example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from flask_lambda_http import FlaskLambdaHttp
from flask_lambda_rest import FlaskLambdaRest
from flask import request
import json

app = FlaskLambdaHttp(__name__)


@app.route('foo', methods=['POST', 'GET'])
def foo():
data = {
'form': request.form.copy(),
'args': request.args.copy()
}
return (
json.dumps(data, indent=4, sort_keys=True),
200,
{'Content-Type': 'application/json'}
)


if __name__ == '__main__':
app.run(debug=True)
111 changes: 111 additions & 0 deletions flask_lambda_http.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Matt Martz
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import sys

try:
from urllib import urlencode
except ImportError:
from urllib.parse import urlencode

from flask import Flask

try:
from cStringIO import StringIO
except ImportError:
try:
from StringIO import StringIO
except ImportError:
from io import StringIO

try: # werkzeug <= 2.0.3
from werkzeug.wrappers import BaseRequest
except: # werkzeug > 2.1
from werkzeug.wrappers import Request as BaseRequest # issue fixed by joranbeasley


__version__ = '0.0.4'


def make_environ(event):
environ = {}

for hdr_name, hdr_value in event['headers'].items():
hdr_name = hdr_name.replace('-', '_').upper()
if hdr_name in ['CONTENT_TYPE', 'CONTENT_LENGTH']:
environ[hdr_name] = hdr_value
continue

http_hdr_name = 'HTTP_%s' % hdr_name
environ[http_hdr_name] = hdr_value

qs = event.get('queryStringParameters', "")

environ['REQUEST_METHOD'] = event['requestContext']['http']['method']
environ['PATH_INFO'] = event['rawPath']
environ['QUERY_STRING'] = urlencode(qs) if qs else ''
environ['REMOTE_ADDR'] = event['requestContext']['http']['sourceIp']
environ['HOST'] = '%(HTTP_HOST)s:%(HTTP_X_FORWARDED_PORT)s' % environ
environ['SCRIPT_NAME'] = ''
environ['SERVER_NAME'] = 'localhost:5000'

environ['SERVER_PORT'] = environ['HTTP_X_FORWARDED_PORT']
environ['SERVER_PROTOCOL'] = 'HTTP/1.1'

environ['CONTENT_LENGTH'] = str(
len(event['body']) if event['body'] else ''
)

environ['wsgi.url_scheme'] = environ['HTTP_X_FORWARDED_PROTO']
environ['wsgi.input'] = StringIO(event['body'] or '')
environ['wsgi.version'] = (1, 0)
environ['wsgi.errors'] = sys.stderr
environ['wsgi.multithread'] = False
environ['wsgi.run_once'] = True
environ['wsgi.multiprocess'] = False

BaseRequest(environ)

return environ


class LambdaResponse(object):
def __init__(self):
self.status = None
self.response_headers = None

def start_response(self, status, response_headers, exc_info=None):
self.status = int(status[:3])
self.response_headers = dict(response_headers)


class FlaskLambdaHttp(Flask):
def __call__(self, event, context):
if not event.get('requestContext', {}).get('http', None):
return super(FlaskLambdaHttp, self).__call__(event, context)

response = LambdaResponse()

body = next(self.wsgi_app(
make_environ(event),
response.start_response
))

return {
'statusCode': response.status,
'headers': response.response_headers,
'body': body
}
9 changes: 6 additions & 3 deletions flask_lambda.py → flask_lambda_rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@
except ImportError:
from io import StringIO

from werkzeug.wrappers import BaseRequest
try: # werkzeug <= 2.0.3
from werkzeug.wrappers import BaseRequest
except: # werkzeug > 2.1
from werkzeug.wrappers import Request as BaseRequest # issue fixed by joranbeasley


__version__ = '0.0.4'
Expand Down Expand Up @@ -88,13 +91,13 @@ def start_response(self, status, response_headers, exc_info=None):
self.response_headers = dict(response_headers)


class FlaskLambda(Flask):
class FlaskLambdaRest(Flask):
def __call__(self, event, context):
if 'httpMethod' not in event:
# In this "context" `event` is `environ` and
# `context` is `start_response`, meaning the request didn't
# occur via API Gateway and Lambda
return super(FlaskLambda, self).__call__(event, context)
return super(FlaskLambdaRest, self).__call__(event, context)

response = LambdaResponse()

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def find_version(*file_paths):

setup(
name='flask-lambda',
version=find_version('flask_lambda.py'),
version=find_version('flask_lambda_rest.py'),
description=('Python module to make Flask compatible with AWS Lambda for '
'creating RESTful applications'),
long_description=long_description,
Expand Down