Skip to content

Commit 2873eca

Browse files
mnapolipgrzesik
authored andcommitted
Switch to HTTP APIs by default for Python examples
1 parent 203964f commit 2873eca

34 files changed

+2175
-24
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.serverless
2+
*.pyc
3+
*.pyo
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
<!--
2+
title: 'AWS Serverless HTTP API with DynamoDB store example in Python'
3+
description: 'This example demonstrates how to setup an HTTP API allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data.'
4+
layout: Doc
5+
framework: v1
6+
platform: AWS
7+
language: Python
8+
authorLink: 'https://github.com/godfreyhobbs'
9+
authorName: 'Godfrey Hobbs'
10+
authorAvatar: 'https://avatars1.githubusercontent.com/u/8434141?v=4&s=140'
11+
-->
12+
# Serverless HTTP API
13+
14+
This example demonstrates how to setup an HTTP API allowing you to create, list, get, update and delete Todos. DynamoDB is used to store the data. This is just an example and of course you could use any data storage as a backend.
15+
16+
## Structure
17+
18+
This service has a separate directory for all the todo operations. For each operation exactly one file exists e.g. `todos/delete.py`. In each of these files there is exactly one function defined.
19+
20+
The idea behind the `todos` directory is that in case you want to create a service containing multiple resources e.g. users, notes, comments you could do so in the same service. While this is certainly possible you might consider creating a separate service for each resource. It depends on the use-case and your preference.
21+
22+
## Use-cases
23+
24+
- API for a Web Application
25+
- API for a Mobile Application
26+
27+
## Setup
28+
29+
```bash
30+
npm install -g serverless
31+
```
32+
33+
## Deploy
34+
35+
In order to deploy the endpoint simply run
36+
37+
```bash
38+
serverless deploy
39+
```
40+
41+
The expected result should be similar to:
42+
43+
```bash
44+
Serverless: Packaging service…
45+
Serverless: Uploading CloudFormation file to S3…
46+
Serverless: Uploading service .zip file to S3…
47+
Serverless: Updating Stack…
48+
Serverless: Checking Stack update progress…
49+
Serverless: Stack update finished…
50+
51+
Service Information
52+
service: serverless-http-api-dynamodb
53+
stage: dev
54+
region: us-east-1
55+
api keys:
56+
None
57+
endpoints:
58+
POST - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos
59+
GET - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos
60+
GET - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos/{id}
61+
PUT - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos/{id}
62+
DELETE - https://45wf34z5yf.execute-api.us-east-1.amazonaws.com/todos/{id}
63+
functions:
64+
update: serverless-http-api-dynamodb-dev-update
65+
get: serverless-http-api-dynamodb-dev-get
66+
list: serverless-http-api-dynamodb-dev-list
67+
create: serverless-http-api-dynamodb-dev-create
68+
delete: serverless-http-api-dynamodb-dev-delete
69+
```
70+
71+
## Usage
72+
73+
You can create, retrieve, update, or delete todos with the following commands:
74+
75+
### Create a Todo
76+
77+
```bash
78+
curl -X POST https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos --data '{ "text": "Learn Serverless" }' -H "Content-Type: application/json"
79+
```
80+
81+
No output
82+
83+
### List all Todos
84+
85+
```bash
86+
curl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos
87+
```
88+
89+
Example output:
90+
```bash
91+
[{"text":"Deploy my first service","id":"ac90feaa11e6-9ede-afdfa051af86","checked":true,"updatedAt":1479139961304},{"text":"Learn Serverless","id":"206793aa11e6-9ede-afdfa051af86","createdAt":1479139943241,"checked":false,"updatedAt":1479139943241}]%
92+
```
93+
94+
### Get one Todo
95+
96+
```bash
97+
# Replace the <id> part with a real id from your todos table
98+
curl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos/<id>
99+
```
100+
101+
Example Result:
102+
```bash
103+
{"text":"Learn Serverless","id":"ee6490d0-aa11e6-9ede-afdfa051af86","createdAt":1479138570824,"checked":false,"updatedAt":1479138570824}%
104+
```
105+
106+
### Update a Todo
107+
108+
```bash
109+
# Replace the <id> part with a real id from your todos table
110+
curl -X PUT https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos/<id> --data '{ "text": "Learn Serverless", "checked": true }' -H "Content-Type: application/json"
111+
```
112+
113+
Example Result:
114+
```bash
115+
{"text":"Learn Serverless","id":"ee6490d0-aa11e6-9ede-afdfa051af86","createdAt":1479138570824,"checked":true,"updatedAt":1479138570824}%
116+
```
117+
118+
### Delete a Todo
119+
120+
```bash
121+
# Replace the <id> part with a real id from your todos table
122+
curl -X DELETE https://XXXXXXX.execute-api.us-east-1.amazonaws.com/todos/<id>
123+
```
124+
125+
No output
126+
127+
## Scaling
128+
129+
### AWS Lambda
130+
131+
By default, AWS Lambda limits the total concurrent executions across all functions within a given region to 1000. The default limit is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. To increase this limit above the default, follow the steps in [To request a limit increase for concurrent executions](http://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html#increase-concurrent-executions-limit).
132+
133+
### DynamoDB
134+
135+
When you create a table, you specify how much provisioned throughput capacity you want to reserve for reads and writes. DynamoDB will reserve the necessary resources to meet your throughput needs while ensuring consistent, low-latency performance. You can change the provisioned throughput and increasing or decreasing capacity as needed.
136+
137+
This is can be done via settings in the `serverless.yml`.
138+
139+
```yaml
140+
ProvisionedThroughput:
141+
ReadCapacityUnits: 1
142+
WriteCapacityUnits: 1
143+
```
144+
145+
In case you expect a lot of traffic fluctuation we recommend to checkout this guide on how to auto scale DynamoDB [https://aws.amazon.com/blogs/aws/auto-scale-dynamodb-with-dynamic-dynamodb/](https://aws.amazon.com/blogs/aws/auto-scale-dynamodb-with-dynamic-dynamodb/)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "aws-http-with-dynamodb",
3+
"version": "1.0.0",
4+
"description": "Serverless HTTP API",
5+
"author": "",
6+
"license": "MIT"
7+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
service: serverless-http-api-dynamodb
2+
frameworkVersion: '2'
3+
4+
provider:
5+
name: aws
6+
runtime: python3.8
7+
environment:
8+
DYNAMODB_TABLE: ${self:service}-${sls:stage}
9+
httpApi:
10+
cors: true
11+
iam:
12+
role:
13+
statements:
14+
- Effect: Allow
15+
Action:
16+
- dynamodb:Query
17+
- dynamodb:Scan
18+
- dynamodb:GetItem
19+
- dynamodb:PutItem
20+
- dynamodb:UpdateItem
21+
- dynamodb:DeleteItem
22+
Resource: "arn:aws:dynamodb:${aws:region}:*:table/${self:provider.environment.DYNAMODB_TABLE}"
23+
24+
functions:
25+
create:
26+
handler: todos/create.create
27+
events:
28+
- httpApi:
29+
path: /todos
30+
method: post
31+
32+
list:
33+
handler: todos/list.list
34+
events:
35+
- httpApi:
36+
path: /todos
37+
method: get
38+
39+
get:
40+
handler: todos/get.get
41+
events:
42+
- httpApi:
43+
path: /todos/{id}
44+
method: get
45+
46+
update:
47+
handler: todos/update.update
48+
events:
49+
- httpApi:
50+
path: /todos/{id}
51+
method: put
52+
53+
delete:
54+
handler: todos/delete.delete
55+
events:
56+
- httpApi:
57+
path: /todos/{id}
58+
method: delete
59+
60+
resources:
61+
Resources:
62+
TodosDynamoDbTable:
63+
Type: 'AWS::DynamoDB::Table'
64+
DeletionPolicy: Retain
65+
Properties:
66+
AttributeDefinitions:
67+
-
68+
AttributeName: id
69+
AttributeType: S
70+
KeySchema:
71+
-
72+
AttributeName: id
73+
KeyType: HASH
74+
BillingMode: PAY_PER_REQUEST
75+
TableName: ${self:provider.environment.DYNAMODB_TABLE}

aws-python-http-api-with-dynamodb/todos/__init__.py

Whitespace-only changes.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import json
2+
import logging
3+
import os
4+
import time
5+
import uuid
6+
7+
import boto3
8+
dynamodb = boto3.resource('dynamodb')
9+
10+
11+
def create(event, context):
12+
data = json.loads(event['body'])
13+
if 'text' not in data:
14+
logging.error("Validation Failed")
15+
raise Exception("Couldn't create the todo item.")
16+
17+
timestamp = str(time.time())
18+
19+
table = dynamodb.Table(os.environ['DYNAMODB_TABLE'])
20+
21+
item = {
22+
'id': str(uuid.uuid1()),
23+
'text': data['text'],
24+
'checked': False,
25+
'createdAt': timestamp,
26+
'updatedAt': timestamp,
27+
}
28+
29+
# write the todo to the database
30+
table.put_item(Item=item)
31+
32+
# create a response
33+
response = {
34+
"statusCode": 200,
35+
"body": json.dumps(item)
36+
}
37+
38+
return response
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import decimal
2+
import json
3+
4+
5+
# This is a workaround for: http://bugs.python.org/issue16535
6+
class DecimalEncoder(json.JSONEncoder):
7+
def default(self, obj):
8+
if isinstance(obj, decimal.Decimal):
9+
return int(obj)
10+
return super(DecimalEncoder, self).default(obj)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import os
2+
3+
import boto3
4+
dynamodb = boto3.resource('dynamodb')
5+
6+
7+
def delete(event, context):
8+
table = dynamodb.Table(os.environ['DYNAMODB_TABLE'])
9+
10+
# delete the todo from the database
11+
table.delete_item(
12+
Key={
13+
'id': event['pathParameters']['id']
14+
}
15+
)
16+
17+
# create a response
18+
response = {
19+
"statusCode": 200
20+
}
21+
22+
return response
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import os
2+
import json
3+
4+
from todos import decimalencoder
5+
import boto3
6+
dynamodb = boto3.resource('dynamodb')
7+
8+
9+
def get(event, context):
10+
table = dynamodb.Table(os.environ['DYNAMODB_TABLE'])
11+
12+
# fetch todo from the database
13+
result = table.get_item(
14+
Key={
15+
'id': event['pathParameters']['id']
16+
}
17+
)
18+
19+
# create a response
20+
response = {
21+
"statusCode": 200,
22+
"body": json.dumps(result['Item'],
23+
cls=decimalencoder.DecimalEncoder)
24+
}
25+
26+
return response
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import json
2+
import os
3+
4+
from todos import decimalencoder
5+
import boto3
6+
dynamodb = boto3.resource('dynamodb')
7+
8+
9+
def list(event, context):
10+
table = dynamodb.Table(os.environ['DYNAMODB_TABLE'])
11+
12+
# fetch all todos from the database
13+
result = table.scan()
14+
15+
# create a response
16+
response = {
17+
"statusCode": 200,
18+
"body": json.dumps(result['Items'], cls=decimalencoder.DecimalEncoder)
19+
}
20+
21+
return response

0 commit comments

Comments
 (0)