├── Readme.md └── goBasics ├── .vscode └── extensions.json ├── exercise └── exercise.txt ├── go.mod ├── imports └── imports.go ├── loops └── main.go ├── main.go ├── maps └── main.go ├── structs └── main.go └── variables └── main.go /Readme.md: -------------------------------------------------------------------------------- 1 | # Frontend Masters Course: Build Go Apps that Scale on AWS 2 | 3 | This is a companion repo containing the code solutions for the [Build Go Apps that Scale on AWS course on Frontend Masters](https://frontendmasters.com/courses/go-aws) 4 | 5 | ## Setup Instructions 6 | 7 | In order to complete this course, you should create an **AWS account**, install **Go**, the **AWS CLI** and the **AWS CDK**. 8 | 9 | ### Install Go (preferably version > = 1.18) 10 | - Download and install Go: [Go Download Page](https://go.dev/dl/) 11 | 12 | ### Install the AWS CLI 13 | - Create an [AWS Account](https://portal.aws.amazon.com/billing/signup) if you don't already have one. 14 | - Install latest version of the [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 15 | - Verify the installation by running `aws --version` 16 | - Configure an AWS user permissions 17 | - Create an [IAM or IAM Identity Center administrative account](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-prereqs.html#getting-started-prereqs-iam) 18 | - Step 3 : Configure the AWS CLI 19 | - Configure [short or long term credentials ](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-quickstart.html) 20 | - Confirm your setup with: `aws s3 ls` and `aws sts get-caller-identity` 21 | 22 | ### CDK installed (use CDK command) 23 | - [Download CDK](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_install) 24 | - Make sure you bootstrap your environment with: 25 | ```bash 26 | cdk bootstrap aws://ACCOUNT-NUMBER/REGION 27 | ``` 28 | Here's [more info](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_bootstrap) about boostrapping the CDK. Your `ACCOUNT-NUMBER` and `REGION` can be found in the AWS console or using the following AWS CLI commands: 29 | - Get your `ACCOUNT-NUMBER` using the following AWS CLI command `aws sts get-caller-identity --query Account --output text` 30 | - Get your `REGION` using the following AWS CLI command `aws configure get region` 31 | 32 | ### CloudWatch Logs 33 | 34 | Some users received CloudWatch logging errors during the API Gateway lessons. Logging to CloudWatch is not required, but you can prevent these errors by [following these steps.](https://repost.aws/knowledge-center/api-gateway-cloudwatch-logs) 35 | 36 | If you dont want logging, you can add `CloudWatchRole: jsii.Bool(true)` to the RestApiProps object. 37 | 38 | ### Gopls Extension 39 | 40 | Download the [Gopls Extension](https://github.com/golang/tools/blob/master/gopls/README.md) for your editor 41 | 42 | ## Code Solutions 43 | 44 | All code for this course is written from scratch. The branches in this repo are code checkpoints for sections within the course: 45 | 46 | * The `main` branch contains everything you need for the **Go Basics** section 47 | * The `chapter_0` branch contains the solution to the **AWS & CDK** section 48 | * branch `chapter_1` branch contains the solution to the **DynamoDB & Insertin Users** section 49 | * branch `chapter_2` branch contains the solution to the **AAPI Gateway & Authentication Routes** section 50 | * branch `chapter_3` branch contains the solution to the **JSON Web Tokens & Protected URLs** section 51 | 52 | **Note:** The code in the above branches may not match what was coded during the course. See the `live_workshop` branch for the final course code. 53 | 54 | ## cURL Commands 55 | 56 | At the end of the course, the API routes are tested with cURL commands. You can copy/paste these commands instead of typing them out. 57 | 58 | ### Register 59 | 60 | ```bash 61 | curl -X POST AWS_SERVER_URL/register -H "Content-Type: application/json" -d '{"username":"USERNAME", "password":"PASSWORD"}' 62 | ``` 63 | 64 | ### Login 65 | 66 | ```bash 67 | curl -X POST AWS_SERVER_URL/login -H "Content-Type: application/json" -d '{"username":"USERNAME", "password":"PASSWORD"}' 68 | ``` 69 | 70 | ### Access Protected Route 71 | 72 | ```bash 73 | curl -X GET AWS_SERVER_URL/protected -H "Content-Type: application/json" -H "Authorization: Bearer JWT_TOKEN" 74 | ``` 75 | 76 | ## Remove infrastructure create with CDK 77 | 78 | To remove the infrastructure created with the AWS CDK, run `cdk destroy`. 79 | 80 | Before running `cdk destroy`, you'll want to ensure you've added `RemovalPolicy: awscdk.RemovalPolicy_DESTROY` in the `awsdynamodb.TableProps`. 81 | -------------------------------------------------------------------------------- /goBasics/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. 3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 4 | 5 | // List of extensions which should be recommended for users of this workspace. 6 | "recommendations": [ 7 | 8 | ], 9 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace. 10 | "unwantedRecommendations": [ 11 | 12 | ] 13 | } -------------------------------------------------------------------------------- /goBasics/exercise/exercise.txt: -------------------------------------------------------------------------------- 1 | - Create a Circle struct with a single field radius of type float64 2 | - Define a circumference method on the circle: 3 | - C = 2*pi*r 4 | - pi = 3.14 5 | - Bonus: 6 | - add a mthod for area 7 | - A = pi*r^2 8 | 9 | 10 | package main 11 | 12 | import ( 13 | "fmt" 14 | ) 15 | 16 | // define the circle struct here 17 | 18 | // define the circumference method here 19 | 20 | func main() { 21 | // create the instance 22 | // call the method and print the result 23 | } -------------------------------------------------------------------------------- /goBasics/go.mod: -------------------------------------------------------------------------------- 1 | module femBasics 2 | 3 | go 1.22.0 4 | -------------------------------------------------------------------------------- /goBasics/imports/imports.go: -------------------------------------------------------------------------------- 1 | package imports 2 | 3 | type Ticket struct { 4 | ID int 5 | Event string 6 | } 7 | 8 | func (t *Ticket) ChangeEvent(newEvent string) { 9 | t.Event = newEvent 10 | } 11 | -------------------------------------------------------------------------------- /goBasics/loops/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "slices" 6 | ) 7 | 8 | func main() { 9 | animals := []string{ 10 | "dog", 11 | "mouse", 12 | } 13 | 14 | animals = append(animals, "cat") 15 | animals = slices.Delete(animals, 2, 3) 16 | fmt.Println(animals) 17 | 18 | for index, animal := range animals { 19 | fmt.Printf("This is animal %s at %d\n", animal, index) 20 | } 21 | 22 | for value := range 10 { 23 | fmt.Println(value) 24 | } 25 | 26 | i := 0 27 | 28 | for i < 5 { 29 | fmt.Println(i) 30 | i++ 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /goBasics/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "femBasics/imports" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | myTicket := imports.Ticket{ 10 | ID: 123, 11 | Event: "theater", 12 | } 13 | 14 | myTicket.ChangeEvent("new event") 15 | 16 | fmt.Println("Hello world") 17 | } 18 | -------------------------------------------------------------------------------- /goBasics/maps/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | myMap := make(map[string]string) 7 | 8 | myMap["key"] = "value" 9 | 10 | for key, value := range myMap { 11 | fmt.Printf("this is key %s and this is value %s\n", key, value) 12 | } 13 | 14 | myNestedMap := map[string]map[string]string{} 15 | 16 | myNestedMap["firstMap"] = map[string]string{ 17 | "nestedMap": "myFirstNestedMap", 18 | } 19 | 20 | fmt.Println(myNestedMap) 21 | 22 | } 23 | -------------------------------------------------------------------------------- /goBasics/structs/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Person struct { 6 | Name string 7 | Age int 8 | } 9 | 10 | func NewPerson(name string, age int) *Person { 11 | return &Person{ 12 | Name: name, 13 | Age: age, 14 | } 15 | } 16 | 17 | func (p *Person) changeName(newName string) { 18 | p.Name = newName 19 | } 20 | 21 | func main() { 22 | myPerson := NewPerson("Melkey", 26) 23 | myPerson.changeName("Marc") 24 | fmt.Printf("Ths is my person %+v\n", myPerson) 25 | 26 | mySlice := []int{1, 2, 3} 27 | 28 | for i := range mySlice { 29 | mySlice[i]++ 30 | } 31 | 32 | fmt.Println("this is the slice", mySlice) 33 | } 34 | -------------------------------------------------------------------------------- /goBasics/variables/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | myName := "Melkey" 7 | myFloat := 100.0 8 | myInt := 10 9 | 10 | fmt.Printf("Hello my name is %s my float is %f and my int is %d\n", myName, myFloat, myInt) 11 | 12 | var myFriendsName string 13 | var myBool bool 14 | var myOtherInt int 15 | 16 | myFriendsName = "Prime" 17 | 18 | fmt.Printf("my friends name is %s my bool is %t and my other int is %d\n", myFriendsName, myBool, myOtherInt) 19 | } 20 | --------------------------------------------------------------------------------