Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
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
6 changes: 6 additions & 0 deletions 6 HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,9 @@ First OSS release

**features**
- added Werkzeug path parameters

4.1.0 (2018-04-12)
+++++++++++++++++++

**features**
- added support for custom domains
36 changes: 30 additions & 6 deletions 36 README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def my_own_get(event):
input_event = {
"body": '{}',
"httpMethod": "GET",
"path": "/"
"resource": "/"
}
result = lambda_handler(event=input_event)
assert result == {"body": '{"this": "will be json dumped"}', "statusCode": 200, "headers":{}}
Expand Down Expand Up @@ -75,7 +75,7 @@ def my_own_get(event):
valid_input_event = {
"body": '{"foo":"bar"}',
"httpMethod": "GET",
"path": "/with-schema/"
"resource": "/with-schema/"
}
result = lambda_handler(event=valid_input_event)
assert result == {"body": '{"this": "will be json dumped"}', "statusCode": 200, "headers":{}}
Expand All @@ -84,7 +84,7 @@ assert result == {"body": '{"this": "will be json dumped"}', "statusCode": 200,
invalid_input_event = {
"body": '{"foo":666}',
"httpMethod": "GET",
"path": "/with-schema/"
"resource": "/with-schema/"
}
result = lambda_handler(event=invalid_input_event)
assert result == {"body": '"Validation Error"', "statusCode": 400, "headers":{}}
Expand Down Expand Up @@ -129,7 +129,7 @@ valid_input_event = {
"foo": "1, 2.2, 3"
},
"httpMethod": "GET",
"path": "/with-params/"
"resource": "/with-params/"
}
result = lambda_handler(event=valid_input_event)
assert result == {"body": '{"foo": [1.0, 2.2, 3.0]}', "statusCode": 200, "headers":{}}
Expand All @@ -153,7 +153,7 @@ def my_own_get(event):
input_event = {
"body": '{}',
"httpMethod": "GET",
"path": "/foo/bar/baz"
"resource": "/foo/bar/baz"
}
result = lambda_handler(event=input_event)
assert result == {"body": '{"this": "will be json dumped"}', "statusCode": 200, "headers":{}}
Expand All @@ -175,12 +175,36 @@ def my_own_get(event, id):
input_event = {
"body": '{}',
"httpMethod": "GET",
"path": "/foo/1234/"
"resource": "/foo/1234/"
}
result = lambda_handler(event=input_event)
assert result == {"body": '{"my-id": 1234}', "statusCode": 200, "headers":{}}
```

Or use the Proxy APIGateway magic endpoint:
```python
from lambdarest import lambda_handler

@lambda_handler.handle("get", path="/bar/<path:path>")
def my_own_get(event, path):
return {"path": path}


##### TEST #####

input_event = {
"body": '{}',
"httpMethod": "GET",
"path": "/foo/bar/baz",
"resource": "/bar/{proxy+}",
"pathParameters": {
"proxy": "bar/baz"
}
}
result = lambda_handler(event=input_event)
assert result == {"body": '{"path": "bar/baz"}', "statusCode": 200, "headers":{}}
```


## Anormal unittest behaviour with `lambda_handler` singleton

Expand Down
30 changes: 23 additions & 7 deletions 30 lambdarest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

__author__ = """sloev"""
__email__ = 'jgv@trustpilot.com'
__version__ = '4.0.0'
__version__ = '4.1.0'


import json
Expand All @@ -13,7 +13,7 @@


__validate_kwargs = {"format_checker": FormatChecker()}
__required_keys = ["httpMethod", "path"]
__required_keys = ["httpMethod", "resource"]


class Response(object):
Expand Down Expand Up @@ -104,7 +104,13 @@ def inner_lambda_handler(event, context=None):

# Save context within event for easy access
event["context"] = context
path = event["path"].lower()
path = event['resource'].lower()

# proxy is a bit weird. We just replace the value in the uri with the
# actual value provided by apigw, and use that
if '{proxy+}' in path:
path = path.replace('{proxy+}', event['pathParameters']['proxy'])

method_name = event["httpMethod"].lower()
func = None
kwargs = {}
Expand All @@ -117,7 +123,7 @@ def inner_lambda_handler(event, context=None):
func = rule.endpoint

# if this is a catch-all rule, don't send any kwargs
if rule.rule == "/<path:path>/":
if rule.rule == "/<path:path>":
kwargs = {}
except NotFound as e:
logging.warning(logging_message.format(
Expand Down Expand Up @@ -173,7 +179,8 @@ def inner(event, *args, **kwargs):
json_data = {
"body": json.loads(event.get("body") or "{}"),
"query": __json_load_query(
event.get("queryStringParameters"))
event.get("queryStringParameters")
)
}
event["json"] = json_data
if schema:
Expand All @@ -182,9 +189,18 @@ def inner(event, *args, **kwargs):
return func(event, *args, **kwargs)

# if this is a catch all url, make sure that it's setup correctly
target_path = path
if path == '*':
target_path = "/<path:path>/"
target_path = "/*"
else:
target_path = path

# replace the * with the werkzeug catch all path
if '*' in target_path:
target_path = target_path.replace('*', '<path:path>')

# make sure the path starts with /
if not target_path.startswith('/'):
raise ValueError("Please configure path with starting slash")

# register http handler function
rule = Rule(target_path, endpoint=inner, methods=[method_name.lower()])
Expand Down
2 changes: 1 addition & 1 deletion 2 setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

setup(
name='lambdarest',
version='4.0.0',
version='4.1.0',
description="pico framework for aws lambda with optional json schema validation",
long_description=readme + '\n\n' + history,
author="jgv",
Expand Down
52 changes: 46 additions & 6 deletions 52 tests/test_lambdarest.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ def assert_called_once(mock):
class TestLambdarestFunctions(unittest.TestCase):
def setUp(self):
self.event = {
"resource": "/test",
"path": "/",
"resource": "/",
"path": "/v1/",
"httpMethod": "POST",
"headers": None,
"queryStringParameters": None,
Expand Down Expand Up @@ -257,20 +257,60 @@ def test_that_specified_path_works(self):
self.lambda_handler.handle("get", path="/foo/bar")(get_mock1) # decorate mock
self.lambda_handler.handle("get", path="/bar/foo")(get_mock2) # decorate mock

self.event["path"] = "/foo/bar"
self.event["resource"] = "/foo/bar"
result1 = self.lambda_handler(self.event, self.context)
assert result1 == {
"body": '"foo"',
"statusCode": 200,
"headers": {}}

self.event["path"] = "/bar/foo"
self.event["resource"] = "/bar/foo"
result2 = self.lambda_handler(self.event, self.context)
assert result2 == {
"body": '"bar"',
"statusCode": 200,
"headers": {}}

def test_that_apigw_with_basepath_works(self):
json_body = {}

self.event["body"] = json.dumps(json_body)
self.event["httpMethod"] = "GET"

get_mock1 = mock.Mock(return_value="foo")

self.lambda_handler.handle("get", path="/foo/bar")(get_mock1) # decorate mock

self.event["path"] = "/v1/foo/bar"
self.event["resource"] = "/foo/bar"
result1 = self.lambda_handler(self.event, self.context)
assert result1 == {
"body": '"foo"',
"statusCode": 200,
"headers": {}}


def test_that_apigw_with_proxy_param_works(self):
json_body = {}

self.event["body"] = json.dumps(json_body)
self.event["httpMethod"] = "GET"

get_mock1 = mock.Mock(return_value="foo")

self.lambda_handler.handle("get", path="/foo/<path:path>")(get_mock1) # decorate mock

self.event["path"] = "/v1/foo/"
self.event["pathParameters"] = {
"proxy": "foobar"
}
self.event["resource"] = "/foo/{proxy+}"
result1 = self.lambda_handler(self.event, self.context)
assert result1 == {
"body": '"foo"',
"statusCode": 200,
"headers": {}}

def test_that_no_path_specified_match_all(self):
random.seed(time.mktime(datetime.now().timetuple()))

Expand All @@ -285,7 +325,7 @@ def test_that_no_path_specified_match_all(self):
r = range(1000)
for i in range(10):
# test with a non-deterministic path
self.event["path"] = "/foo/{}/".format(random.choice(r))
self.event["resource"] = "/foo/{}/".format(random.choice(r))
result = self.lambda_handler(self.event, self.context)
assert result == {
"body": '"foo"',
Expand All @@ -297,7 +337,7 @@ def test_exception_in_handler_should_be_reraised(self):
json_body = {}
self.event["body"] = json.dumps(json_body)
self.event["httpMethod"] = "GET"
self.event["path"] = "/foo/bar"
self.event["resource"] = "/foo/bar"

def divide_by_zero(_):
return 1/0
Expand Down
Morty Proxy This is a proxified and sanitized view of the page, visit original site.