My Cloud Resume
Tags: aws, cloud, cloudskills, serverless
Published: 2022-01-08 20:19:55


![flowchart for this project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wg1wlojm698kntcrysox.jpeg)
<hr>
# How We Got Here
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;As a professional musician, it would be putting it lightly to say the past two years have been hard. Tired of waiting for my career to return to normal, I dug deep and decided it was time to pursue my first ever passion: Tech - I did lots of research and decided Cloud technology is what I wanted to learn. That lead me to the [Cloud Resume Challenge](https://cloudresumechallenge.dev/docs/the-challenge/aws/) by Forrest Brazeal. 
<hr>
## The Challenge

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The challenge asks that you at least get the AWS Cloud Practitioner certification and then build a full stack application that serves your resume on the web with a visitor counter. 
I decided instead to start by studying for and passing the AWS Solutions Architect Associate exam, then began putting the challenge together.

I first started by creating some basic HTML & CSS placeholder documents that would be replaced with a final product later. These were uploaded to a public S3 bucket with static webhosting enabled.

Now that the content was public through S3, I purchased a custom domain through Route53 and requested a SSL/TLS certificate with ACM for said domain, and then created a CloudFront distribution to serve all of the static content through the domain with HTTPS.

Next, I set out to make the visitor counter - at first, being very confused how all of the pieces fit together - I started by building out each AWS service I needed manually; the DynamoDB table, the Lambda function, and the API Gateway. The database was easy enough, but I was stunned as I started writing my Lambda function; I chose Python for Boto3 library, and I got stuck on the documentation for quite some time, but eventually I was able to incrementally update the DynamoDB table item each time I executed the Lambda code. I then created a REST API using API Gateway and returned to the Lambda and added some code for the Lambda function to get the DynamoDB item and return the value.

Once visiting my API both updated the table item and returned the freshly incremented value, I wrote a small piece of client-side JavaScript to fetch the return value from the API and inject it into the body of my HTML.

The visitor counter is working! However, the challenge calls for you to build your backend infrastructure as code. I decided to use Terraform - this is where I spent the bulk of my time on the project - over several days, I read and reread the documentation trying to meet every contingency for my infrastructure to deploy and having my visitor counter working immediately. Easily the most difficult part was setting up the API such that it was CORS enabled, but I was eventually able to figure it out and received a huge reward after I typed 'terraform apply' for the last time.

With the app working and my infrastructure defined in code, it was time to push the frontend and backend to their respective GitHub repositories and set up CI/CD pipelines for each. Thankfully, GitHub Actions made this very straightforward - I was able to find all the actions I needed premade; for the backend I used an action for zipping up my Lambda Python code, one for uploading the .zip to S3 so it can be deployed by Terraform, and finally an action for installing, initiating, and applying the Terraform code(This also required setting up a Terraform Cloud account to save the Terraform state). The frontend pipeline was much simpler; using the S3 upload action again followed by an action to invalidate the CloudFront distribution ensuring the latest content is available. For security and function, I used GitHub Secrets to store AWS access keys and bucket names. Now, each time I push something new to each repo, my application is updated and continues to work with missing a beat.

Finally, I created the final draft of my resume with HTML, styled it with CSS, and pushed it to production through my pipeline
<hr>
## What I Didn't Get to Do (but Will in the Future)

- Using one GitHub Repository for the whole stack - The challenge called for two separate repos, but I think a single repo with more specifically tailored GitHub Actions would be easier to manage.

- Integrate automated testing - I wrote a small smoke test using Cypress that passes if my API returns the proper values. Since I manually tested the code until I knew it was working and then  pushed it, I never *needed* to integrate the testing into my pipeline, but this would be especially useful for an application that will be updated with any regularity.

- Semantic HTML & Responsive CSS - in its current state, the HTML and CSS are just code vomit - they work on desktop browsers and that is about it. Since viewing will likely occur on mobile devices, I think it is important that I update this as soon as possible.

- Caching - currently, the CloudFront distribution does not have caching setup properly for the application, so the visitor counter will continue updating with each refresh(and with testing too). I acknowledge that this is unideal and plan to figure out the best way to fix this ASAP.

- Infrastructure as Code for the frontend - If I was able to troubleshoot all of the issues and make Terraform work for my backend, I could certainly do it for my frontend. This would allow me to control all of my current infrastructure in one place and would work with a single repo as mentioned above.
<hr>

## Final Thoughts

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;My understanding of how web applications work went from lots and lots of small pieces of information that didn't really fit together to larger chunks of working knowledge. This challenge truly helped me connect the pieces and grasp where each part of the stack begins and where it ends. I plan to return to this project in the near future to apply new things that I learn and fix the things that could be better.

<hr>
#### You can view the finished product here:
[resume.jordanardoin.com](resume.jordanardoin.com)