Python routing mini-framework for AWS Lambda with optional JSON-schema validation.
lambda_handler
function constructor with built-in dispatcher- Decorator to register functions to handle HTTP methods
- Optional JSON-schema input validation using same decorator
-
devgrok.com: Create a Private Microservice Using an Application Load Balancer
Article about how to use lambdarest with AWS Application Load Balancer
-
rockset.com: Building a Serverless Microservice Using Rockset and AWS Lambda
Article about how to set up lambdarest in AWS infrastructure
Other articles? add them here
Install the package from PyPI using pip:
pip install lambdarest
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":{}}
Optionally you can validate an incoming JSON body against a JSON schema:
from lambdarest import lambda_handler
my_schema = {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"body":{
"type": "object",
"properties": {
"foo": {
"type": "string"
}
}
}
}
}
@lambda_handler.handle("get", path="/with-schema/", schema=my_schema)
def my_own_get(event):
return {"this": "will be json dumped"}
##### TEST #####
valid_input_event = {
"body": '{"foo":"bar"}',
"httpMethod": "GET",
"resource": "/with-schema/"
}
result = lambda_handler(event=valid_input_event)
assert result == {"body": '{"this": "will be json dumped"}', "statusCode": 200, "headers":{}}
invalid_input_event = {
"body": '{"foo":666}',
"httpMethod": "GET",
"resource": "/with-schema/"
}
result = lambda_handler(event=invalid_input_event)
assert result == {"body": 'Validation Error', "statusCode": 400, "headers":{}}
Query parameters are also analyzed and validatable with JSON schemas. Query arrays are expected to be comma separated, all numbers are converted to floats.
from lambdarest import lambda_handler
my_schema = {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"query":{
"type": "object",
"properties": {
"foo": {
"type": "array",
"items": {
"type": "number"
}
}
}
}
}
}
@lambda_handler.handle("get", path="/with-params/", schema=my_schema)
def my_own_get(event):
return event["json"]["query"]
##### TEST #####
valid_input_event = {
"queryStringParameters": {
"foo": "1, 2.2, 3"
},
"httpMethod": "GET",
"resource": "/with-params/"
}
result = lambda_handler(event=valid_input_event)
assert result == {"body": '{"foo": [1.0, 2.2, 3.0]}', "statusCode": 200, "headers":{}}
You can also specify which path to react on for individual handlers using the path
param:
from lambdarest import lambda_handler
@lambda_handler.handle("get", path="/foo/bar/baz")
def my_own_get(event):
return {"this": "will be json dumped"}
##### TEST #####
input_event = {
"body": '{}',
"httpMethod": "GET",
"resource": "/foo/bar/baz"
}
result = lambda_handler(event=input_event)
assert result == {"body": '{"this": "will be json dumped"}', "statusCode": 200, "headers":{}}
And you can specify path parameters as well, which will be passed as keyword arguments:
from lambdarest import lambda_handler
@lambda_handler.handle("get", path="/foo/<int:id>/")
def my_own_get(event, id):
return {"my-id": id}
##### TEST #####
input_event = {
"body": '{}',
"httpMethod": "GET",
"resource": "/foo/1234/"
}
result = lambda_handler(event=input_event)
assert result == {"body": '{"my-id": 1234}', "statusCode": 200, "headers":{}}
Or you can specify more complex parametrized resource path and get parameteres as arguments:
from lambdarest import lambda_handler
@lambda_handler.handle("get", path="/object/<int:object_id>/props/<string:foo>/get")
def my_own_get(event, object_id, foo):
return [{"object_id": int(object_id)}, {"foo": foo}]
##### TEST #####
input_event = {
"body": '{}',
"httpMethod": "GET",
"path": "/v1/object/777/props/bar/get",
"resource": "/object/{object_id}/props/{foo}/get",
"pathParameters": {
"object_id": "777",
"foo":"bar"
}
}
result = lambda_handler(event=input_event)
assert result == {"body": '[{"object_id": 777}, {"foo": "bar"}]', "statusCode": 200, "headers":{}}
Or use the Proxy APIGateway magic endpoint:
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": "/v1/bar/baz",
"resource": "/bar/{proxy+}",
"pathParameters": {
"proxy": "bar/baz"
}
}
result = lambda_handler(event=input_event)
assert result == {"body": '{"path": "bar/baz"}', "statusCode": 200, "headers":{}}
In order to use it with Application Load Balancer you need to create your own lambda_handler and not use the singleton:
from lambdarest import create_lambda_handler
lambda_handler = create_lambda_handler(application_load_balancer=True)
@lambda_handler.handle("get", path="/foo/<int:id>/")
def my_own_get(event, id):
return {"my-id": id}
##### TEST #####
input_event = {
"body": '{}',
"httpMethod": "GET",
"resource": "/foo/1234/"
}
result = lambda_handler(event=input_event)
assert result == {"body": '{"my-id": 1234}', "statusCode": 200, "headers":{}, "statusDescription": "HTTP OK", "isBase64Encoded": False}
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.
This package uses Make to install requirements and run tests.
Use the following commands to install requirements and run test-suite:
$ make setup test
For more info see Contributing...
@nabrosimoff, @elviejokike, @eduardomourar, @devgrok, @AlbertoTrindade, @paddie, @svdgraaf, @simongarnier, @martinbuberl, @adamelmore, @sloev
And by the way, we have a Code Of Friendlyhood!