Are CORS errors like pulling teeth? A dentist completes the Cloud Resume Challenge
Tags: aws, cloud, serverless, cloudresumechallenge
Published: 2022-02-21 15:07:46

****



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jxlaucv7fsljevi4xj48.jpg)

Back in the day when the Apple Macintosh came out, I was obsessed with computers. I owned a book that covered basic computer knowledge and memorized it cover to cover. That year, I asked for a computer for Christmas, and when I saw the box under the tree, I was ecstatic. It was my family’s new color TV. 

I’ve pondered that moment frequently for the past two years. If that had been a computer, would I have become a chemical engineer at 20 and a dentist 16 years later? I employed some amateur psychoanalysis, hoping that the third time’s the charm, and realized I love learning. But, when the learning stagnates, so do I. Luckily, I also realized IT is the motherlode of continuous learning.

So, I started studying web dev, programming with Python, ethically capturing flags, and researching the cloud. And, I found another book: [The Cloud Resume Challenge Book](https://forrestbrazeal.gumroad.com/l/cloud-resume-challenge-book). I eagerly accepted the challenge and began by completing [Adrian Cantrill’s](https://learn.cantrill.io/) AWS Solutions Architect Associate course. Then, I started his AWS Developer Associate course. And, ‘yada, yada, yada’. I just ‘yada’d’ more studying. I was doing what a former dental student who survived a 52 credit hour semester feels comfortable doing: studying and more studying. But, even in dental school, there comes a time to put the books down and put the gloves on. The [challenge] (https://forrestbrazeal.com/2020/04/23/the-cloud-resume-challenge/) began.  

**Frontend:**

**[The Resume](https://resume.prod.curiouscloud.me/):  HTML | CSS | JS**
I began with the HTML boilerplate and used grid template areas for a responsive design. [Kevin Powell’s](https://www.youtube.com/channel/UCJZv4d5rbIKd4QHMPkcABCw) YouTube videos were extremely helpful with the design, but I ended up using a partial CSS snippet for the blog post button. I also used a free trial at CodeAcademy Pro to review asynchronous JavaScript to code the API call. 

**Frontend Infrastructure:  S3 | CloudFront | Route 53 | ACM**

First, I got the infrastructure working in the console. I quickly set up the S3 static website and secured it with the CloudFront OAI. I used Certificate Manager to securely deliver my custom domain from Route 53. But the custom domain didn’t work until I got my CNAME records sorted out. 

**The Backend:  API Gateway | Lambda | Python | DynamoDB** 

The backend is where the forceps meet the enamel. But I didn’t realize how confusing it was going to be until I started wrapping my head around AWS’s documentation. Eventually, I figured out the difference between the client vs. resource and found [botodocs](https://botodocs.com/#/). After research into how to target the visitor count from the Lambda response and json.dumps vs stringify, I thought my Lambda function was done.

So, I moved on to API Gateway. I set up a REST API and Lambda proxy integration, enabled CORS, and deployed the API. I successfully tested the API within the AWS console and then Postman. But, when I refreshed my resume, I promptly got my first CORS error. A significant amount of time later, I added the proper headers to my Lambda function’s response. With my Lambda function actually done, I happily watched the visitor counter tick upward.  

**Infrastructure as Code:  Terraform**

The tooth was loosening a bit. This was a milestone that I was looking forward to. Nothing says cloud to me like IaC. Since it’s the industry standard, I used Terraform instead of SAM. I followed KodeKloud’s Terraform for Beginners’ course up through the AWS section and then started going through the Hashicorp docs and tutorials. The clarity of having the docs in one place and a couple of helpful tutorials allowed me to complete the frontend with minimal growing pains. 

After finishing the frontend, I was fairly comfortable with the syntax, using variables, and using data sources to forego using heredocs for IAM policies. Then came the Lambda resource and the ZIP file vs container debate. The challenge is about learning outside your comfort zone. So, after getting WSL2, and Docker Desktop setup, I containerized my Lambda function and hosted it with ECR. Once I discovered the necessity of the policy attachment resource, I was ready for CORS: the boss fight. 

Our hypothetical tooth was loose to the point it should move further out of the socket, but wasn’t. That’s when you suspect there’s a root tip shaped like a fishhook. Normally, you can see that on the x-ray. But, x-rays are two-dimensional, so if it’s pointing toward or away from the film, you’re in for a surprise. Even with a couple of good tutorials, slaying the CORS monster in Terraform was a challenge. Figuring out how to add OPTIONS and ANY to the root path, like I had in the console, was painful. 

**CI/CD and End to End Testing:  Git | GitHub Actions | Cypress**

After getting the IaC to work on my dev account, I switched everything over to my prod account. Since I had automated both the frontend and backend at that point, I started a new GitHub repository and pushed. The next issue may have been averted if I had used Terraform Cloud for my remote state instead of S3 and DynamoDB. Gitignoring the .tfvars file meant my variables weren't getting read by GitHub Actions unless I added them all to the secrets repository. I attempted to use git-crypt instead, but ran into a nasty cygwin1.dll error. I pivoted, added the ECR URI to repository secrets, and unignored the .tfvars file. But, my GitHub Actions failed on Terraform deploy. Once I figured out how to use the same domain over two AWS accounts, the Terraform deploy worked. However, my Cypress test of the API did not. I was looking at package-lock.json in my repo, but it was being reported as missing. So, I used a containerized version of Cypress in the workflow and watched with amazement as both the Terraform deploy and Cypress test actions passed. Suddenly, I truly grasped the utility of Docker and containers in a way that wasn’t possible from studying. 

So, are CORS errors like pulling teeth? Yes, I think the entire challenge was like pulling a molar with splayed and hooked roots. But learning some theory, and patiently and methodically working through issues that arise during practice, eventually leads to success. 

Throughout the challenge, the breadth and depth of knowledge it imparted amazed me. But, the biggest surprise and gift was that it taught me the best way to learn in the tech world. There’s a place for courses and traditional studying to form a basis. But, now I understand ‘just in time’ learning, which I first heard on [DevOps for Developers’](https://www.youtube.com/c/DevOpsForDevelopers) YouTube channel. Learning what’s necessary and ‘just in time’ is what gets projects done. That’s alright. For once, there are plenty of wondrous rabbit holes in the doing. I can’t wait to explore them in my next project.

Right now though, I have to study for all those AWS certs.