Skip to content

Commit 14ce1bd

Browse files
author
Hans Klunder
committed
Initial publish
1 parent fc22071 commit 14ce1bd

File tree

2 files changed

+482
-0
lines changed

2 files changed

+482
-0
lines changed

README.md

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
Docker Voting App done Serverless Style
2+
=======================================
3+
4+
# Introduction
5+
I was reading [Deploy the Voting App to AWS ECS with Fargate] by Tony Pujals where he describes how to run the [Docker Voting app demo] on AWS using [AWS Fargate]
6+
7+
[Deploy the Voting App to AWS ECS with Fargate]:https://medium.com/@tonypujals/deploy-the-voting-app-to-aws-ecs-with-fargate-
8+
[Docker Voting app demo]:https://github.com/subfuzion/docker-voting-app-nodejs
9+
[AWS Fargate]:https://aws.amazon.com/fargate/
10+
11+
Of course I understand that the Docker Voting app is a showcase of Docker technology and that it's not the most exciting application from a business perspective. I also understand that people want to show how you can take Docker technology to AWS. However in my mind I started wondering: if I would take this to AWS would I be following the same path ? Or would I go Serverless ?
12+
13+
Given the title: I went Serverless!
14+
15+
The voting application is recreated using AWS ApiGateway and AWS DynamoDB only. The queue service could be implemented using SNS, however one typically uses a queue to ensure scalability of the database or to allow for maintenance. Both are handled by AWS DynamoDB automatically.
16+
17+
# Creating the schema
18+
Looking at the sources of the voting app there are two endpoints:
19+
- POST /vote where you can post a vote by posting JSON like `{"vote":"a"}` or `{"vote":"b"}`
20+
- GET /results which will give you results like:
21+
```json
22+
{
23+
"success" : true,
24+
"result" : {
25+
"a" : 0,
26+
"b" : 0
27+
}
28+
}
29+
```
30+
31+
Creating a JSON schema produces the following for /vote
32+
33+
```json
34+
{
35+
"Vote": {
36+
"type": "object",
37+
"required": ["vote"],
38+
"properties": {
39+
"vote": {
40+
"type": "string",
41+
"enum": ["a", "b"]
42+
}
43+
},
44+
"title": "Vote Schema"
45+
}
46+
}
47+
```
48+
and for /results
49+
50+
```json
51+
{
52+
"type": "object",
53+
"properties": {
54+
"success": {
55+
"type": "boolean"
56+
},
57+
"result": {
58+
"type": "object",
59+
"properties": {
60+
"a": {
61+
"type": "integer"
62+
},
63+
"b": {
64+
"type": "integer"
65+
}
66+
}
67+
}
68+
},
69+
"title": "Results schema"
70+
}
71+
```
72+
73+
Loading these in APIgateway ensures for /vote that only valid POST requests are accepted.
74+
75+
# DynamoDB
76+
The DynamoDB instance with partion key `topic` only holds one record with `topic` value `default` and a numeric value for `a` and `b`
77+
78+
# APIgateway integration
79+
A succesful POST operation must result in a increment of the counter for the subject of the vote in the database.
80+
This is achieved by adding the following integration request mapping template to the POST operation:
81+
```json
82+
{
83+
"TableName" : "VoteAppDynamoDBTable",
84+
"Key": {
85+
"topic": {
86+
"S":"default"
87+
}
88+
},
89+
"UpdateExpression": "ADD $input.path('$.vote') :inc",
90+
"ExpressionAttributeValues": {
91+
":inc": {
92+
"N": "1"
93+
}
94+
}
95+
}
96+
```
97+
This, together with the rest of the integration configuration, will transform the POST operation into a call to DynamoDB to increment the number of votes for the subject provided.
98+
99+
Then when pulling results the GET operation needs to be transformed into a query on DynamoDB using an integration request mapping template
100+
```json
101+
{
102+
"TableName" : "VoteAppDynamoDBTable",
103+
"KeyConditionExpression": "topic = :v1",
104+
"ExpressionAttributeValues": {
105+
":v1": {
106+
"S": "default"
107+
}
108+
}
109+
}
110+
```
111+
and the response needs to be mapped to the schema listed above using an integration response mapping template
112+
```
113+
#set($inputRoot = $input.path('$'))
114+
{
115+
"success" : true,
116+
"result" : {
117+
#if($inputRoot.Count==0)
118+
"a" : 0,
119+
"b" : 0
120+
#{else}
121+
"a" : #if($inputRoot.Items[0].a=="")0#{else}$inputRoot.Items[0].a.N#end,
122+
"b" : #if($inputRoot.Items[0].b=="")0#{else}$inputRoot.Items[0].b.N#end
123+
#end
124+
}
125+
}
126+
```
127+
As long as no votes have been casted it could be that the whole record does not exist yet or that `a` or `b` is still non-existent. This template takes care of these edge cases.
128+
129+
The full template can be found [here].
130+
131+
[here]:voteApp-CF-template.json

0 commit comments

Comments
 (0)