I found the Cloud Resume Challenge by Forrest Brazeal while looking for ideas to practise my AWS skills. I first became interested in tech after taking part in an ERP integration project and cross-functional end-to-end testing in my previous order management role. There were tech people who worked with the mysterious backend and as soon as we couldn't make something work, they would go and adjust things directly at the backend. I never got to see the mysterious backend and I was curious and fascinated. My journey to tech began. I learned fullstack development and joined an AWS learning path. And now, cloud computing is not only the next big thing, but I also find it technically super interesting. The chance of creating a full stack project in the cloud, automating it and even running my own end-to-end testing, just seemed like something I absolutely wanted to do - no more tech people to call, backend is what I make with it.
The challenge consists of several chunks and multiple options along the way to choose your own apporach:
- Getting Cloud Practitioner Certification.
- Resume in HTML/CSS deployed in S3 as a static website.
- AWS CloudFront Distribution in front of the S3 bucket.
- Custom DNS domain name.
- Javascript calling the API and displaying a visitor counter on the website.
- API Gateway that accepts requests from your web app and communicates with the database through Lambda function.
- Database in DynamoDB to save and update the visitor counter.
- Lambda function that updates the database and returns an updated value to API Gateway.
- Cypress tests to complete end-to-end testing for your code.
- Infrastructure as Code.
- CI/CD.
- Blog post.
The below diagram explains the structure of my project:
Frontend
After setting up AWS SSO to keep my account secure, I started with the first step. At this point my aim was to configure all my resources manually by clicking around in the AWS web console.
For my website I used a template, which I customized slightly to suit my own needs. I set up CloudFront distribution, which accessed my S3 bucket and had it's own HTTPS address. Next I got my custom domain from CloudFlare, which I also use to manage DNS. I issued a certificate through ACM (Amazon Certificate Manager) and added it and the custom domain to my CloudFront Distribution. A few trial and error here and there and that was pretty much what it took to get the frontend working.
I also wrote Javascript for my S3 bucket and tested it locally with a locally run NodeJS backend. However it was time to park that for the moment and start working on the structure of the backend.
Backend
I started by creating a new DynamoDB table, which was easy as the database only had to have one value. I selected on-demand paying plan, which shouldn't create any costs with this level of usage. Next I went to create a Lambda function with NodeJS runtime. I had to choose whether to create two functions to get and update the item or to use only one function to do both. I decided it's more purposeful to use only one function in this case, as I could simply take advantage of the the 'ReturnValues' that the function returns after updating the database.
After Lambda was working, it was time to create my API Gateway. First I had to choose between REST API and HTTP API, which was slightly confusing and I initially chose HTTP API, yet ended up changing my setup to REST API at the later stages of the project as the CDK construct for HTTP API gateway was experimental and creating REST API seemed more straightforward. Anyway, I got the whole thing working with Postman and was ready to connect the frontend and backend together. Obviously things didn't work the first or second time and the CORS-error became a very familiar sight. But here we were in the end, the whole full stack project was working and I could navigate to my custom domain and see the updated visitor count displayed on my website.
End-to-end testing
I had never used Cypress before so I had to do some learning before installing Cypress locally and starting to write my first tests with Typescript. I kept my tests simple and there are definitely a lot more tests I could go and write to improve the process. The tests also helped me notice a few things that were missing from the set up - such as custom error responses in CloudFront. Anyway, improving my tests later on will be a breeze, because of what I implemented next.
IaC and CI/CD
The challenge description suggests that you first complete the whole project using the AWS web console and once you're ready, you go back and define your resources as 'infrastructure as code' that can be deployed automatically. That's what I did and I can definitely agree it's a great way to learn and by the time I started with IaC I knew exactly what I had to do.
There are plenty of tools to choose from and I decided to go with AWS CDK (Cloud Development Kit) as it allows you to use Typescript to code your infrastructure and it just seemed to me like a logical way of doing things. I created new CDK apps for frontend and backend, added there all the code I had written in previous steps and used Typescript to define my application resources. Obviously it took a few failed deployments and rollbacks to get everything working, but I was still quite surprised how straigthforward it actually was. After that all I needed to do was to set up GitHub Actions to automate deployments and run Cypress tests.
Final thoughts
So what do I have as an end result? Two repos: one for frontend and another for backend, each including the AWS CDK app source code and each automatically deployed whenever a new commit is pushed. Such a nice and simple thing when it all comes together, yet it has taken endless hours of figuring out all the pieces of the puzzle. But I honestly can't imagine a better way to learn.
To see the final product please visit my portfolio website and GitHub repos for backend code and frontend code.