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
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 ?
Given the title: I went Serverless!
The first iteration was on AWS using AWS ApiGateway and AWS DynamoDB only. And then I figured that it would be fun to try it on Google Cloud as well. Given the simplicity of the problem I went for Google Firebase.
Looking at the sources of the original voting app there are two endpoints:
- POST /vote where you can post a vote by posting JSON like
{"vote":"a"}
or{"vote":"b"}
- GET /results which will give you results like:
{
"success": true,
"result": {
"a": 0,
"b": 0
}
}
Firebase does nothing with automatic schema validation like the AWS API ApiGateway does. So creating a JSON schema is of no use here. Given the specific formats of the API a simple route to a solution is to use Firebase Functions with data stored using Firebase Realtime Database.
And then it becomes a rather simple exercise:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
exports.vote = functions.https.onRequest((request, response) => {
const vote = request.body.vote;
if (vote === "a" || vote === "b") {
const resultsRef = admin.database().ref("/result");
const ref = resultsRef.child(vote);
ref.transaction(currentVotes => {
// If result.{vote} has never been set, currentVotes will be `null`.
return (currentVotes || 0) + 1;
});
response.send("You voted: " + vote);
} else {
response.status(400).send("Invalid request");
}
});
exports.results = functions.https.onRequest((request, response) => {
var results = {
success: true,
result: {
a: 0,
b: 0
}
};
return admin
.database()
.ref("/result")
.once("value")
.then(snapshot => {
const resultsData = snapshot.val();
results.result.a = resultsData.a || 0;
results.result.b = resultsData.b || 0;
response.json(results);
return;
})
.catch(_ => {
response.json(results);
});
});
The data might not exist in the database yet when /results
is being called
therefore this function takes care of that using resultsData.a || 0
and
through the .catch
handler.
The complete code can be found in functions/index.js. All the rest of the project is auto generated using firebase-tools.