├── 02-study ├── .gitignore ├── snippetbox │ ├── ui │ │ ├── static │ │ │ ├── img │ │ │ │ ├── logo.png │ │ │ │ └── favicon.ico │ │ │ ├── js │ │ │ │ └── main.js │ │ │ └── css │ │ │ │ └── main.css │ │ └── html │ │ │ ├── partials │ │ │ └── nav.html │ │ │ ├── pages │ │ │ └── home.html │ │ │ └── base.html │ ├── go.mod │ ├── go.sum │ ├── internal │ │ └── models │ │ │ ├── errors.go │ │ │ └── snippets.go │ ├── cmd │ │ └── web │ │ │ ├── routes.go │ │ │ ├── helpers.go │ │ │ ├── main.go │ │ │ └── handlers.go │ └── NOTES.md ├── snippets.sql └── README.md ├── 03-study ├── 07-web-service-sample │ ├── menu.txt │ └── main.go ├── go.mod ├── go.sum ├── 01-hello-world-sample │ └── main.go ├── .vscode │ └── launch.json ├── 02-simple-types-conversions-sample │ └── main.go ├── 06-cli-app-sample │ └── main.go ├── 08-arrays-sample │ └── main.go ├── 03-arithmetic-comparison-sample │ └── main.go ├── 09-slices-sample │ └── main.go ├── 04-constants-iota-sample │ └── main.go ├── 05-pointers-sample │ └── main.go ├── 11-structs-sample │ └── main.go ├── 10-map-sample │ └── main.go ├── NOTES.md └── README.md ├── 01-study ├── interfaces-go │ ├── stringer-sample.go │ ├── book-sample.go │ └── customer-sample.go ├── pointers-go │ ├── creature-sample-pointer.go │ └── creature-sample.go └── README.md ├── LICENSE └── README.md /02-study/.gitignore: -------------------------------------------------------------------------------- 1 | notes.txt -------------------------------------------------------------------------------- /02-study/snippetbox/ui/static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaucia86/golang-studies/HEAD/02-study/snippetbox/ui/static/img/logo.png -------------------------------------------------------------------------------- /02-study/snippetbox/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/glaucia86/snippetbox 2 | 3 | go 1.21 4 | 5 | require github.com/go-sql-driver/mysql v1.7.1 // indirect 6 | -------------------------------------------------------------------------------- /02-study/snippetbox/ui/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaucia86/golang-studies/HEAD/02-study/snippetbox/ui/static/img/favicon.ico -------------------------------------------------------------------------------- /03-study/07-web-service-sample/menu.txt: -------------------------------------------------------------------------------- 1 | Coffee 2 | Espresso 3 | Cappuccino 4 | 5 | Hot Tea 6 | Chai Tea 7 | Chai Latte 8 | 9 | Hot Chocolate 10 | -------------------------------------------------------------------------------- /03-study/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/glaucia86/03-study 2 | 3 | go 1.21.0 4 | 5 | require golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect 6 | -------------------------------------------------------------------------------- /02-study/snippetbox/ui/html/partials/nav.html: -------------------------------------------------------------------------------- 1 | {{define "nav"}} 2 | 3 | 6 | {{end}} -------------------------------------------------------------------------------- /02-study/snippetbox/ui/html/pages/home.html: -------------------------------------------------------------------------------- 1 | {{define "title"}}Home{{end}} 2 | 3 | {{define "main"}} 4 |

Latest Snippets

5 |

There's nothing to see here yet!

6 | {{end}} -------------------------------------------------------------------------------- /02-study/snippetbox/go.sum: -------------------------------------------------------------------------------- 1 | github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= 2 | github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= 3 | -------------------------------------------------------------------------------- /03-study/go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM= 2 | golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= 3 | -------------------------------------------------------------------------------- /02-study/snippetbox/ui/static/js/main.js: -------------------------------------------------------------------------------- 1 | var navLinks = document.querySelectorAll("nav a"); 2 | for (var i = 0; i < navLinks.length; i++) { 3 | var link = navLinks[i] 4 | if (link.getAttribute('href') == window.location.pathname) { 5 | link.classList.add("live"); 6 | break; 7 | } 8 | } -------------------------------------------------------------------------------- /02-study/snippetbox/internal/models/errors.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: internal/models/errors.go 3 | * description: file responsible for the errors of the application. 4 | * data: 01/02/2024 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package models 9 | 10 | import "errors" 11 | 12 | var ErrNoRecord = errors.New("models: no matching record found") 13 | -------------------------------------------------------------------------------- /02-study/snippets.sql: -------------------------------------------------------------------------------- 1 | -- Create a `snippets` table. 2 | CREATE TABLE snippets ( 3 | id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, 4 | title VARCHAR(100) NOT NULL, 5 | content TEXT NOT NULL, 6 | created DATETIME NOT NULL, 7 | expires DATETIME NOT NULL 8 | ); 9 | 10 | -- Add an index on the created column. 11 | CREATE INDEX idx_snippets_created ON snippets(created); -------------------------------------------------------------------------------- /03-study/01-hello-world-sample/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: main.go 3 | * description: file responsible for running the application. 4 | * data: 12/28/2023 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | // go.mod file should be present in the workspace folder 9 | 10 | package main 11 | 12 | import "fmt" 13 | 14 | func main() { 15 | fmt.Println("Hello World!") 16 | } 17 | -------------------------------------------------------------------------------- /03-study/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Debug - Web Service", 9 | "type": "go", 10 | "request": "launch", 11 | "mode": "auto", 12 | "program": "${workspaceFolder}/07-web-service-sample/main.go", 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /03-study/07-web-service-sample/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: main.go 3 | * description: file responsible for running the application. 4 | * data: 12/29/2023 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import ( 11 | "io" 12 | "net/http" 13 | "os" 14 | ) 15 | 16 | func main() { 17 | http.HandleFunc("/", Handler) 18 | http.ListenAndServe(":3000", nil) 19 | } 20 | 21 | func Handler(w http.ResponseWriter, r *http.Request) { 22 | f, _ := os.Open("./menu.txt") 23 | io.Copy(w, f) 24 | } 25 | -------------------------------------------------------------------------------- /03-study/02-simple-types-conversions-sample/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: main.go 3 | * description: file responsible for running the application. 4 | * data: 12/28/2023 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import "fmt" 11 | 12 | func main() { 13 | a := "Glaucia Lemos" 14 | fmt.Println(a) 15 | 16 | var b int = 99 17 | fmt.Println(b) 18 | 19 | var c = true 20 | fmt.Println(c) 21 | 22 | d := 3.1415 23 | fmt.Println(d) 24 | 25 | var e int = int(d) 26 | fmt.Println(e) 27 | } 28 | -------------------------------------------------------------------------------- /03-study/06-cli-app-sample/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: main.go 3 | * description: file responsible for running the application. 4 | * data: 12/29/2023 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import ( 11 | "bufio" 12 | "fmt" 13 | "os" 14 | "strings" 15 | ) 16 | 17 | func main() { 18 | fmt.Println("What would you like me to scream?") 19 | in := bufio.NewReader(os.Stdin) 20 | s, _ := in.ReadString('\n') 21 | s = strings.TrimSpace(s) 22 | s = strings.ToUpper(s) 23 | fmt.Println(s + "!") 24 | } 25 | -------------------------------------------------------------------------------- /01-study/interfaces-go/stringer-sample.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: stringer-sample.go 3 | * description: file responsible for explaining the usage of 'fmt.Stringer' interface in Go. 4 | * data: 12/24/2023 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import "fmt" 11 | 12 | type Animal struct { 13 | Name string 14 | Age uint 15 | } 16 | 17 | func (a Animal) String() string { 18 | return fmt.Sprintf("%v (%d years)", a.Name, a.Age) 19 | } 20 | 21 | func main() { 22 | animal := Animal{ 23 | Name: "Prince", 24 | Age: 3, 25 | } 26 | 27 | fmt.Println(animal) 28 | } 29 | -------------------------------------------------------------------------------- /03-study/08-arrays-sample/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: main.go 3 | * description: file responsible for running the application. 4 | * data: 01/03/2024 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import "fmt" 11 | 12 | func main() { 13 | var arr [3]string 14 | fmt.Println(arr) // [ ] 15 | 16 | arr = [3]string{"Coffee", "Espresso", "Capuccino"} 17 | fmt.Println(arr) // [Coffee Espresso Capuccino] 18 | 19 | fmt.Println(arr[1]) // Espresso 20 | arr[1] = "Mocha" 21 | fmt.Println(arr) // [Coffee Mocha Capuccino] 22 | 23 | arr2 := arr 24 | fmt.Println(arr2) // [Coffee Mocha Capuccino] 25 | 26 | } 27 | -------------------------------------------------------------------------------- /03-study/03-arithmetic-comparison-sample/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: main.go 3 | * description: file responsible for running the application. 4 | * data: 12/28/2023 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import "fmt" 11 | 12 | func main() { 13 | a, b := 5, 2 14 | 15 | fmt.Println("Soma: ", a+b) 16 | fmt.Println("Subtração: ", a-b) 17 | fmt.Println("Multiplicação: ", a*b) 18 | fmt.Println("Divisão: ", a/b) 19 | fmt.Println("Módulo: ", a%b) 20 | 21 | fmt.Println("Conversão", float32(a)/float32(b)) 22 | 23 | fmt.Println("Igualdade: ", a == b) 24 | fmt.Println("Diferença: ", a != b) 25 | fmt.Println("Maior: ", a > b) 26 | } 27 | -------------------------------------------------------------------------------- /03-study/09-slices-sample/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: main.go 3 | * description: file responsible for running the application. 4 | * data: 01/10/2024 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | "slices" 13 | ) 14 | 15 | func main() { 16 | var s []string 17 | fmt.Println(s) // [ ] 18 | 19 | s = []string{"Coffee", "Espresso", "Capuccino"} 20 | fmt.Println(s) // [Coffee Espresso Capuccino] 21 | 22 | s = append(s, "Hot Chocolate", "Hot Tea") 23 | fmt.Println(s) 24 | 25 | slices.Delete(s, 1, 2) 26 | fmt.Println(s) 27 | 28 | // fmt.Println(s[1]) // Espresso 29 | // s[1] = "Mocha" 30 | // fmt.Println(s) // [Coffee Mocha Capuccino] 31 | 32 | // s2 := s 33 | // fmt.Println(s, s2) 34 | } 35 | -------------------------------------------------------------------------------- /01-study/pointers-go/creature-sample-pointer.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: creature-sample-pointer.go 3 | * description: file responsible for explaining the usage of * and & in Go. 4 | * data: 12/24/2023 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import "fmt" 11 | 12 | type Creature struct { 13 | Species string 14 | } 15 | 16 | func main() { 17 | var creature Creature = Creature{ 18 | Species: "shark", 19 | } 20 | 21 | fmt.Printf("1)%+v\n", creature) // {Species:shark} 22 | changeCreature(&creature) // {Species:jellyfish} 23 | fmt.Printf("3)%+v\n", creature) // now prints {Species:jellyfish} 24 | } 25 | 26 | func changeCreature(creature *Creature) { 27 | creature.Species = "jellyfish" 28 | fmt.Printf("2)%+v\n", creature) 29 | } 30 | -------------------------------------------------------------------------------- /03-study/04-constants-iota-sample/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: main.go 3 | * description: file responsible for running the application. 4 | * data: 12/28/2023 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import "fmt" 11 | 12 | func main() { 13 | const a = 42 14 | var i int = a // 42 15 | var f64 float64 = a // 42 16 | 17 | fmt.Println(i, f64) 18 | 19 | // iota sample 20 | const c = iota 21 | fmt.Println(c) 22 | 23 | const ( 24 | d = 2 * 5 25 | e // 2 * 5 26 | f = iota // porque está na posição 2 27 | g // 3. Porque está na posição 3 28 | h = 10 * iota // 10 * 4. Por que? Porque pegou o valor da posição 4 (iota) e multiplicou por 10 29 | ) 30 | 31 | fmt.Println(d, e, f, g, h) 32 | } 33 | -------------------------------------------------------------------------------- /01-study/pointers-go/creature-sample.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: creature-sample.go 3 | * description: file responsible for explaining the usage of * and & in Go. 4 | * data: 12/24/2023 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import "fmt" 11 | 12 | type Creature struct { 13 | Species string 14 | } 15 | 16 | func main() { 17 | var creature Creature = Creature{ 18 | Species: "shark", 19 | } 20 | 21 | fmt.Printf("1)%+v\n", creature) // {Species:shark} 22 | changeCreature(creature) // {Species:jellyfish} 23 | fmt.Printf("3)%+v\n", creature) // should be {Species:jellyfish} but prints {Species:shark} 24 | } 25 | 26 | func changeCreature(creature Creature) { 27 | creature.Species = "jellyfish" 28 | fmt.Printf("2)%+v\n", creature) 29 | } 30 | -------------------------------------------------------------------------------- /02-study/snippetbox/cmd/web/routes.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: cmd/web/routes.go 3 | * description: file responsible for handling the routes of the application. 4 | * data: 12/27/2023 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import "net/http" 11 | 12 | func (app *application) routes() *http.ServeMux { 13 | mux := http.NewServeMux() 14 | 15 | // Configuração do FileServer para servir arquivos estáticos. 16 | fileServer := http.FileServer(http.Dir("./ui/static/")) 17 | mux.Handle("/static/", http.StripPrefix("/static", fileServer)) 18 | 19 | // Demais rotas da aplicação 20 | mux.HandleFunc("/", app.home) 21 | mux.HandleFunc("/snippet/view", app.snippetView) 22 | mux.HandleFunc("/snippet/create", app.snippetCreate) 23 | 24 | return mux 25 | } 26 | -------------------------------------------------------------------------------- /03-study/05-pointers-sample/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: main.go 3 | * description: file responsible for running the application. 4 | * data: 12/28/2023 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import "fmt" 11 | 12 | func main() { 13 | s := "Hello World!" 14 | 15 | p := &s // p recebe o endereço de memória da variável s 16 | fmt.Println(p) // 0xc000098020 - endereço de memória 17 | fmt.Println(*p) // Hello World! - valor da variável 18 | 19 | *p = "Hello, Gophers!" // alterando o valor da variável através do ponteiro 20 | fmt.Println(*p) // Hello Go! - novo valor da variável 21 | 22 | p = new(string) // p recebe o endereço de memória de uma nova variável do tipo string 23 | fmt.Println(p) // 0xc000096050 - endereço de memória 24 | fmt.Println(*p) // "" - valor da variável 25 | } 26 | -------------------------------------------------------------------------------- /02-study/snippetbox/ui/html/base.html: -------------------------------------------------------------------------------- 1 | {{ define "base" }} 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{template "title" .}} - Snippetbox 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |

Snippetbox

17 |
18 | 19 | {{template "nav" .}} 20 | 21 |
22 | {{template "main" .}} 23 |
24 |
Powered by Go
25 | 26 | 27 | 28 | 29 | {{end}} -------------------------------------------------------------------------------- /01-study/interfaces-go/book-sample.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: book-sample.go 3 | * description: file responsible for explaining the usage of 'fmt.Stringer' interface in Go. 4 | * data: 12/24/2023 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | "log" 13 | "strconv" 14 | ) 15 | 16 | type Book struct { 17 | Title string 18 | Author string 19 | } 20 | 21 | func (b Book) String() string { 22 | return fmt.Sprintf("Book: %s - %s", b.Title, b.Author) 23 | } 24 | 25 | type Count int 26 | 27 | func (c Count) String() string { 28 | return strconv.Itoa(int(c)) 29 | } 30 | 31 | func WriteLog(s fmt.Stringer) { 32 | log.Print(s.String()) 33 | } 34 | 35 | func main() { 36 | book := Book{ 37 | "Alice in Wonderland", 38 | "Lewis Carroll", 39 | } 40 | 41 | WriteLog(book) 42 | 43 | count := Count(3) 44 | WriteLog(count) 45 | } 46 | -------------------------------------------------------------------------------- /03-study/11-structs-sample/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: main.go 3 | * description: file responsible for running the application. 4 | * data: 01/10/2024 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import ( 11 | "bufio" 12 | "fmt" 13 | "os" 14 | "strings" 15 | ) 16 | 17 | func main() { 18 | fmt.Println("Please, select an option") 19 | fmt.Println("1) Print menu") 20 | in := bufio.NewReader(os.Stdin) 21 | choice, _ := in.ReadString('\n') 22 | choice = strings.TrimSpace(choice) 23 | 24 | type menuItem struct { 25 | name string 26 | prices map[string]float64 27 | } 28 | 29 | menu := []menuItem{ 30 | {name: "Coffee", prices: map[string]float64{"small:": 1.50, "medium": 2.00, "large": 2.50}}, 31 | {name: "Tea", prices: map[string]float64{"small:": 1.00, "medium": 1.50, "large": 2.00}}, 32 | } 33 | 34 | fmt.Println(menu) 35 | } 36 | -------------------------------------------------------------------------------- /02-study/snippetbox/cmd/web/helpers.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: cmd/web/helpers 3 | * description: file responsible for handling the errors of the application. 4 | * data: 12/27/2023 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import ( 11 | "net/http" 12 | "runtime/debug" 13 | ) 14 | 15 | func (app *application) serverError(w http.ResponseWriter, r *http.Request, err error) { 16 | var ( 17 | method = r.Method 18 | uri = r.URL.RequestURI() 19 | trace = string(debug.Stack()) 20 | ) 21 | 22 | app.logger.Error(err.Error(), "method", method, "uri", uri, "trace", trace) 23 | http.Error(w, "Internal Server Error", http.StatusInternalServerError) 24 | } 25 | 26 | func (app *application) clientError(w http.ResponseWriter, status int) { 27 | http.Error(w, http.StatusText(status), status) 28 | } 29 | 30 | func (app *application) notFound(w http.ResponseWriter) { 31 | app.clientError(w, http.StatusNotFound) 32 | } 33 | -------------------------------------------------------------------------------- /01-study/interfaces-go/customer-sample.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: customer-sample.go 3 | * description: file responsible for explaining the usage of 'fmt.Stringer' interface in Go. 4 | * data: 12/24/2023 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import ( 11 | "bytes" 12 | "encoding/json" 13 | "io" 14 | "log" 15 | "os" 16 | ) 17 | 18 | type Customer struct { 19 | Name string 20 | Age int 21 | } 22 | 23 | func (c *Customer) WriteJSON(wj io.Writer) error { 24 | js, err := json.Marshal(c) 25 | if err != nil { 26 | return err 27 | } 28 | 29 | _, err = wj.Write(js) 30 | return err 31 | } 32 | 33 | func main() { 34 | customer := &Customer{ 35 | Name: "Alice", 36 | Age: 21, 37 | } 38 | 39 | var buf bytes.Buffer 40 | err := customer.WriteJSON(&buf) 41 | 42 | if err != nil { 43 | log.Fatal(err) 44 | } 45 | 46 | f, err := os.Create("/tmp/customer") 47 | if err != nil { 48 | log.Fatal(err) 49 | } 50 | 51 | defer f.Close() 52 | 53 | err = customer.WriteJSON(f) 54 | if err != nil { 55 | log.Fatal(err) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Glaucia Lemos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /03-study/10-map-sample/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: main.go 3 | * description: file responsible for running the application. 4 | * data: 01/10/2024 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import "fmt" 11 | 12 | func main() { 13 | var m map[string][]string 14 | fmt.Println(m) // map[] 15 | 16 | m = map[string][]string{ 17 | "coffee": {"Espresso", "Capuccino", "Mocha"}, 18 | "tea": {"Hot Tea", "Chai Tea", "Chai Latte"}, 19 | } 20 | 21 | fmt.Println(m) // map[coffee:[Espresso Capuccino Mocha] tea:[Hot Tea Chai Tea Chai Latte]] 22 | fmt.Println(m["coffee"]) // [Espresso Capuccino Mocha] 23 | 24 | m["water"] = []string{"Sparkling"} 25 | fmt.Println(m) // map[coffee:[Espresso Capuccino Mocha] tea:[Hot Tea Chai Tea Chai Latte] water:[Sparkling]] 26 | 27 | delete(m, "tea") 28 | fmt.Println(m) // map[coffee:[Espresso Capuccino Mocha] water:[Sparkling]] 29 | 30 | fmt.Println(m["tea"]) 31 | v, ok := m["tea"] 32 | fmt.Println(v, ok) // [] false 33 | 34 | m2 := m 35 | m2["coffee"] = []string{"Coffee"} 36 | m["tea"] = []string{"Hot Tea"} 37 | 38 | fmt.Println(m) 39 | fmt.Println(m2) 40 | } 41 | -------------------------------------------------------------------------------- /02-study/snippetbox/cmd/web/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: cmd/web/main.go 3 | * description: file responsible for running the application. 4 | * data: 01/01/2024 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import ( 11 | "database/sql" 12 | "flag" 13 | "log/slog" 14 | "net/http" 15 | "os" 16 | "github.com/glaucia86/snippetbox/internal/models" 17 | _ "github.com/go-sql-driver/mysql" 18 | ) 19 | 20 | type application struct { 21 | logger *slog.Logger 22 | snippets *models.SnippetModel 23 | } 24 | 25 | func main() { 26 | 27 | addr := flag.String("addr", ":4000", "HTTP network address") 28 | dsn := flag.String("dsn", "web:Br@zil2024@tcp(127.0.0.1:3306)/snippetbox?parseTime=true", "MySQL DSN") 29 | flag.Parse() 30 | 31 | logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) 32 | 33 | db, err := openDB(*dsn) 34 | if err != nil { 35 | logger.Error(err.Error()) 36 | os.Exit(1) 37 | } 38 | 39 | defer db.Close() 40 | 41 | app := &application{ 42 | logger: logger, 43 | snippets: &models.SnippetModel{DB: db}, 44 | } 45 | 46 | logger.Info("Starting the server on port", "addr", *addr) 47 | 48 | err = http.ListenAndServe(*addr, app.routes()) 49 | logger.Error(err.Error()) 50 | os.Exit(1) 51 | } 52 | 53 | func openDB(dsn string) (*sql.DB, error) { 54 | db, err := sql.Open("mysql", dsn) 55 | if err != nil { 56 | return nil, err 57 | } 58 | 59 | err = db.Ping() 60 | if err != nil { 61 | db.Close() 62 | return nil, err 63 | } 64 | 65 | return db, nil 66 | } 67 | -------------------------------------------------------------------------------- /03-study/NOTES.md: -------------------------------------------------------------------------------- 1 | # # Pluralsight Course: Go Fundamentals by Mike Van Sickle (NOTES) 2 | 3 | ## Simple Data Types 4 | 5 | - Strings: 6 | - Ex.: `"Hello, World!"` 7 | - Numbers: 8 | - int: `int` 9 | - unsigned integers: `uint` 10 | - floating point numbers: `float32`, `float64` 11 | - complex numbers: `complex64`, `complex128` 12 | - Booleans: `true` or `false` 13 | - Errors: The error built-in type is the conventional interface for representing an error condition, with the nil value representing no error. 14 | - Ex.: `errors.New("Something went wrong")` 15 | 16 | ## When to use `iota`? 17 | 18 | - When you want to create a set of related constants that increment in value. 19 | - When you want to create a set of related constants that share the same type. 20 | - When you want to create a set of related constants that share the same type and are initialized with a value that is incremented in value. 21 | - When you need to create a set of related constants that share the same type and are initialized with a value that is incremented in value, but you don't want to have to manually assign the value of each constant. 22 | 23 | Ex.: 24 | 25 | ```go 26 | const ( 27 | Sunday = iota 28 | Monday 29 | Tuesday 30 | Wednesday 31 | Thursday 32 | Friday 33 | Saturday 34 | ) 35 | 36 | const ( 37 | Running = 1 << iota 38 | Swimming 39 | Cycling 40 | Skiing 41 | Canoeing 42 | ) 43 | ``` 44 | 45 | ## CLI Tools in Standard Library 46 | 47 | - `os`: Operating system functionality 48 | - `stdin`, `stdout`, `stderr` 49 | - `fmt`: Formatting and printing 50 | - `Scan*`, `Print*`, `Sprint*`, `Fprint*` 51 | -------------------------------------------------------------------------------- /03-study/README.md: -------------------------------------------------------------------------------- 1 | # Pluralsight Course: Go Fundamentals by Mike Van Sickle 2 | 3 | ## 📚 What I studied in this book? 4 | 5 | - [x] Course Overview 6 | - [x] Course Overview 7 | - [x] Getting Up and Running 8 | - [x] Introduction 9 | - [x] Prerequisites and Expected Outcomes 10 | - [x] Getting Up and Running 11 | - [x] Demo: Installing Go 12 | - [x] Setting Up a Code editor 13 | - [x] Demo: Installing and Configuring Visual Studio Code 14 | - [x] Demo: Your First Go Program 15 | - [x] Course Plan 16 | - [x] Summary 17 | - [x] Variables and Simple Data Types 18 | - [x] Introduction 19 | - [x] Simple Data Types 20 | - [x] The String Type 21 | - [x] Numeric Types 22 | - [x] Boolean Types 23 | - [x] Error Types 24 | - [x] Finding Documentation for Built-in Types 25 | - [x] Declaring Variables 26 | - [x] Type Conversions 27 | - [x] Demo: Using Simple Types and Type Conversions 28 | - [x] Common Arithmetic Operators 29 | - [x] Common Comparison Operators 30 | - [x] Demo: Using Arithmetic and Comparison Operators 31 | - [x] Constants, Constant Expressions, and Iota 32 | - [x] Demo: Constants, Constant Expressions, and Iota 33 | - [x] Pointers 34 | - [x] Demo: Creating and Using Pointers 35 | - [x] Summary 36 | - [x] Creating and Debugging Programs 37 | - [x] Introduction 38 | - [x] Concept: Command-line interfaces 39 | - [x] CLI Tools 40 | - [x] Demo: Building a CLI Application 41 | - [x] Concept: Web Services 42 | - [x] Demo: Building a Web Service 43 | - [x] Demo: Debugging a Program 44 | - [x] Summary 45 | - [x] Aggregate Data Types 46 | - [x] Introduction 47 | - [x] Concept: Array Types 48 | - [x] Creating and Using Arrays 49 | - [x] Demo: Arrays 50 | - [x] Concept: Slice Types 51 | - [x] Creating and Using Slices 52 | - [x] Demo: Slices 53 | - [x] Concept: Map Types 54 | - [x] Creating and Using Maps 55 | - [x] Demo: Maps 56 | - [x] Concept: Struct Types 57 | - [x] Creating and Using Structs 58 | - [x] Demo: Structs 59 | - [x] Summary -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Golang Studies 2 | 3 | Repository created to store all the studies and projects developed in Golang. 4 | 5 | [![bit-go.png](https://i.postimg.cc/s204FQ2b/bit-go.png)](https://postimg.cc/GBGyGpGj) 6 | 7 | ## 🚀 Resources Used 8 | 9 | * **[Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=javascript-0000-gllemos)** 10 | * **[Golang](https://golang.org/doc/install)** 11 | * **[Extension Golang - Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-vscode.Go&WT.mc_id=javascript-0000-gllemos)** 12 | 13 | 14 | ## 📚 Studies Guide 15 | 16 | - **[Aprenda Golang do Zero! Desenvolva uma Aplicação Completa - Udemy Course](https://www.udemy.com/course/aprenda-golang-do-zero-desenvolva-uma-aplicacao-completa)** 17 | - **[01-study](./01-study/README.md)** 18 | - **[Book: Let's Go Professional Package by Alex Edwards](https://lets-go.alexedwards.net/#packages)** 19 | - **[02-study](./02-study/README.md)** 20 | - **[Course: Go Fundamentals by Mike Van Sickle](https://app.pluralsight.com/library/courses/fundamentals-go/table-of-contents)** 21 | - **[03-study](./03-study/README.md)** 22 | 23 | 24 | ## ❗️Important Resources 25 | 26 | I will be listing here some important links and resources that will direct you to: documentation, free courses, books and content related to Golang. Below is a list of these resources, which are considered recommended readings, courses or books: 27 | 28 | - ✅ **[Official Documentation - Golang](http://www.golangbr.org/doc/)** 29 | - ✅ **[Azure for Golang Developers](https://docs.microsoft.com/azure/developer/go/?WT.mc_id=javascript-0000-gllemos)** 30 | - ✅ **[Debugging Golang in Visual Studio Code](https://github.com/golang/vscode-go/blob/master/docs/debugging.md)** 31 | 32 | ## ❓ I have questions... What do I do?! 33 | 34 | If you have questions about the codes developed during this series of articles, feel free to open a **[ISSUE HERE](https://github.com/glaucia86/golang-studies/issues)**. As soon as possible, I will be answering all the questions you have! 35 | -------------------------------------------------------------------------------- /01-study/README.md: -------------------------------------------------------------------------------- 1 | # Udemy Course: Aprenda Golang do Zero! Desenvolva uma Aplicação Completa - Udemy Course 2 | 3 | Here you will find all the studies and projects developed in the Golang course `Aprenda Golang do Zero! Desenvolva uma Aplicação Completa - Udemy Course`. 4 | 5 | > source of the course **[here](https://www.udemy.com/course/aprenda-golang-do-zero-desenvolva-uma-aplicacao-completa)** 6 | 7 | ## How to run the projects? 8 | 9 | To run the projects, you need to have the Go installed on your machine. If you don't have it, you can download it [here](https://golang.org/dl/). 10 | 11 | After installing Go, you can run the projects using the command: 12 | 13 | ```bash 14 | go run .go 15 | ``` 16 | 17 | If you want to compile the project, you can use the command: 18 | 19 | ```bash 20 | go build .go 21 | ``` 22 | 23 | And if you want to see the compiled project, you can use the command: 24 | 25 | ```bash 26 | ./ 27 | ``` 28 | 29 | ## What I studied in this book? 30 | 31 | - [x] Seção 01 32 | - [x] Boas Vindas! 33 | - [x] Instalando Go e Visual Studio Code 34 | - [x] Escrevendo seu primeiro Hello World! 35 | 36 | - [ ] Seção 02: Fundamentos da Linguagem 37 | - [ ] Pacotes 38 | - [ ] Pacotes Externos 39 | - [ ] Variáveis 40 | - [ ] Tipos de Dados 41 | - [ ] Funções 42 | - [ ] Operadores 43 | - [ ] Structs 44 | - [ ] Herança 45 | - [ ] Ponteiros 46 | - [ ] Arrays e Slices 47 | - [ ] Arrays Internos 48 | - [ ] Maps 49 | - [ ] Estruturas de Controle 50 | - [ ] Switch 51 | - [ ] Loops 52 | - [ ] Funções com Retorno Nomeado 53 | - [ ] Funções Variáticas 54 | - [ ] Funções Anônimas 55 | - [ ] Funções Recursivas 56 | - [ ] Defer 57 | - [ ] Panic e Recover 58 | - [ ] Função Closure 59 | - [ ] Funções com Ponteiros 60 | - [ ] Função Init 61 | - [ ] Métodos 62 | - [ ] Interfaces 63 | - [ ] Interfaces como Tipo Genérico 64 | 65 | - [ ] Seção 03: Mini Aplicação de Linha de Comando 66 | - [ ] 67 | - [ ] 68 | - [ ] 69 | - [ ] 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /02-study/snippetbox/internal/models/snippets.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: internal/models/snippets.go 3 | * description: file responsible for the model of the application. 4 | * data: 01/05/2024 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package models 9 | 10 | import ( 11 | "database/sql" 12 | "errors" 13 | "time" 14 | ) 15 | 16 | type Snippet struct { 17 | ID int 18 | Title string 19 | Content string 20 | Created time.Time 21 | Expires time.Time 22 | } 23 | 24 | type SnippetModel struct { 25 | DB *sql.DB 26 | } 27 | 28 | func (m *SnippetModel) Insert(title string, content string, expires int) (int, error) { 29 | stmt := `INSERT INTO snippets (title, content, created, expires) 30 | VALUES(?, ?, UTC_TIMESTAMP(), DATE_ADD(UTC_TIMESTAMP(), INTERVAL ? DAY))` 31 | 32 | result, err := m.DB.Exec(stmt, title, content, expires) 33 | if err != nil { 34 | return 0, nil 35 | } 36 | 37 | id, err := result.LastInsertId() 38 | if err != nil { 39 | return 0, nil 40 | } 41 | 42 | return int(id), nil 43 | } 44 | 45 | func (m *SnippetModel) Get(id int) (Snippet, error) { 46 | 47 | stmt := `SELECT id, title, content, created, expires FROM snippets 48 | WHERE expires > UTC_TIMESTAMP() AND id = ?` 49 | 50 | row := m.DB.QueryRow(stmt, id) 51 | 52 | var s Snippet 53 | 54 | err := row.Scan(&s.ID, &s.Title, &s.Content, &s.Created, &s.Expires) 55 | if err != nil { 56 | if errors.Is(err, sql.ErrNoRows) { 57 | return Snippet{}, ErrNoRecord 58 | } else { 59 | return Snippet{}, nil 60 | } 61 | } 62 | 63 | return s, nil 64 | } 65 | 66 | func (m *SnippetModel) LatestSnippets() ([]Snippet, error) { 67 | stmt := `SELECT id, title, content, created, expires FROM snippets 68 | WHERE expires > UTC_TIMESTAMP() ORDER BY id DESC LIMIT 10` 69 | 70 | rows, err := m.DB.Query(stmt) 71 | if err != nil { 72 | return nil, err 73 | } 74 | 75 | defer rows.Close() 76 | 77 | var snippets []Snippet 78 | 79 | for rows.Next() { 80 | var s Snippet 81 | 82 | err := rows.Scan(&s.ID, &s.Title, &s.Content, &s.Created, &s.Expires) 83 | if err != nil { 84 | return nil, err 85 | } 86 | 87 | snippets = append(snippets, s) 88 | } 89 | 90 | if err = rows.Err(); err != nil { 91 | return nil, err 92 | } 93 | 94 | return snippets, nil 95 | } 96 | -------------------------------------------------------------------------------- /02-study/snippetbox/cmd/web/handlers.go: -------------------------------------------------------------------------------- 1 | /** 2 | * file: cmd/web/handlers.go 3 | * description: file responsible for handling the routes of the application. 4 | * data: 01/05/2024 5 | * author: Glaucia Lemos 6 | */ 7 | 8 | package main 9 | 10 | import ( 11 | "errors" 12 | "fmt" 13 | //"html/template" 14 | "net/http" 15 | "strconv" 16 | 17 | "github.com/glaucia86/snippetbox/internal/models" 18 | ) 19 | 20 | func (app *application) home(w http.ResponseWriter, r *http.Request) { 21 | 22 | if r.URL.Path != "/" { 23 | app.notFound(w) 24 | return 25 | } 26 | 27 | snippets, err := app.snippets.LatestSnippets() 28 | if err != nil { 29 | app.serverError(w, r, err) 30 | return 31 | } 32 | 33 | for _, snippet := range snippets { 34 | fmt.Fprintf(w, "%v\n", snippet) 35 | } 36 | 37 | // files := []string{ 38 | // "./ui/html/base.html", 39 | // "./ui/html/partials/nav.html", 40 | // "./ui/html/pages/home.html", 41 | // } 42 | 43 | // ts, err := template.ParseFiles(files...) 44 | 45 | // if err != nil { 46 | // app.serverError(w, r, err) 47 | // return 48 | // } 49 | 50 | // err = ts.ExecuteTemplate(w, "base", nil) 51 | // if err != nil { 52 | // app.serverError(w, r, err) 53 | // } 54 | } 55 | 56 | func (app *application) snippetView(w http.ResponseWriter, r *http.Request) { 57 | id, err := strconv.Atoi(r.URL.Query().Get("id")) 58 | if err != nil || id < 1 { 59 | app.notFound(w) 60 | return 61 | } 62 | 63 | snippet, err := app.snippets.Get(id) 64 | if err != nil { 65 | if errors.Is(err, models.ErrNoRecord) { 66 | app.notFound(w) 67 | } else { 68 | app.serverError(w, r, err) 69 | } 70 | 71 | return 72 | } 73 | 74 | fmt.Fprintf(w, "%v", snippet) 75 | } 76 | 77 | func (app *application) snippetCreate(w http.ResponseWriter, r *http.Request) { 78 | 79 | if r.Method != http.MethodPost { 80 | w.Header().Set("Allow", http.MethodPost) 81 | app.clientError(w, http.StatusMethodNotAllowed) 82 | return 83 | } 84 | 85 | title := "O snail" 86 | content := "O snail\nClimb Mount Fuji,\nBut slowly, slowly!\n\n– Kobayashi Issa" 87 | expires := 7 88 | 89 | id, err := app.snippets.Insert(title, content, expires) 90 | if err != nil { 91 | app.serverError(w, r, err) 92 | return 93 | } 94 | 95 | http.Redirect(w, r, fmt.Sprintf("/snippet/view?id=%d", id), http.StatusSeeOther) 96 | } 97 | -------------------------------------------------------------------------------- /02-study/snippetbox/NOTES.md: -------------------------------------------------------------------------------- 1 | # Notas 2 | 3 | Aqui segue algumas notas de estudo sobre o projeto `snippetbox`. 4 | 5 | ## Go Modules 6 | 7 | Para criar um modulo em Go, vá até a pasta do projeto. No nosso caso, `snippetbox`. E dentro dele, execute o comando: 8 | 9 | ```bash 10 | go mod init github.com/yourusername/snippetbox 11 | ``` 12 | 13 | Isso irá criar um arquivo `go.mod` na pasta do projeto. Esse arquivo é responsável por gerenciar as dependências do projeto. 14 | 15 | ## Lista de `Constants` 16 | 17 | Podemos consultar a lista de `constants` disponíveis no pacote `net/http`, através do link: **[Constants](https://pkg.go.dev/net/http#pkg-constants)** 18 | 19 | ## Como estruturar um projeto em Go 20 | 21 | Basta seguir a documentação oficial do Go, que explica como podemos estruturar um projeto. 22 | 23 | **[Server project](https://go.dev/doc/modules/layout#server-project)** 24 | 25 | ### Projeto refatorado 26 | 27 | O projeto foi refatorado. Assim sendo, para executar o projeto, basta executar o comando: 28 | 29 | ```bash 30 | go run ./cmd/web/ 31 | ``` 32 | 33 | Depois, basta acessar o endereço: **[http://localhost:4000](http://localhost:4000)** e aparecerá a página inicial do projeto. 34 | 35 | **[Code Developed - commit](https://github.com/glaucia86/golang-studies/commit/8fb8ba757a301559576fda3056697f09db028913)** 36 | 37 | ## Significado de `http.Handler` em Go 38 | 39 | `http.Handler` é uma interface que define o método `ServeHTTP` que recebe um `http.ResponseWriter` e um `*http.Request` como argumentos. 40 | 41 | Exemplo: 42 | 43 | ```go 44 | type Handler interface { 45 | ServeHTTP(ResponseWriter, *Request) 46 | } 47 | ``` 48 | 49 | Mais detalhes, acesse o link: **[http.Handler](https://pkg.go.dev/net/http#Handler)** 50 | 51 | ## Significado de `http.ListenAndServe` em Go 52 | 53 | `http.ListenAndServe` é uma função que recebe dois argumentos: um endereço de rede e um `http.Handler` e retorna um erro. 54 | 55 | Exemplo: 56 | 57 | ```go 58 | package main 59 | 60 | import ( 61 | "fmt" 62 | "log" 63 | "net/http" 64 | ) 65 | 66 | func main() { 67 | // Hello World, the web server 68 | 69 | helloHandler := func(w http.ResponseWriter, req *http.Request) { 70 | io.WriteString(w, "hello, world!\n") 71 | } 72 | 73 | http.HandleFunc("/hello", helloHandler) 74 | log.Fatal(http.ListenAndServe(":4000", nil)) 75 | } 76 | ``` 77 | 78 | ## Lidando com environment variables em Go 79 | 80 | Para lidar com environment variables em Go, basta importar o pacote `os` e utilizar a função `os.Getenv()`. 81 | 82 | Exemplo: 83 | 84 | ```go 85 | package main 86 | 87 | import ( 88 | "fmt" 89 | "log" 90 | "net/http" 91 | "os" 92 | ) 93 | 94 | func main() { 95 | // Hello World, the web server 96 | 97 | helloHandler := func(w http.ResponseWriter, req *http.Request) { 98 | io.WriteString(w, "hello, world!\n") 99 | } 100 | 101 | http.HandleFunc("/hello", helloHandler) 102 | log.Fatal(http.ListenAndServe(os.Getenv("PORT"), nil)) 103 | } 104 | ``` 105 | 106 | ## Exemplo de Closures for dependency injection 107 | 108 | > observação: seguir o exemplo feito **[AQUI](https://gist.github.com/alexedwards/5cd712192b4831058b21)** e **[AQUI](https://www.alexedwards.net/blog/organising-database-access)** 109 | 110 | ## How to execute MySQL at WSL2? 111 | 112 | Para executar o MySQL no WSL2, basta executar o seguinte comando: 113 | 114 | ```bash 115 | sudo service mysql start 116 | ``` 117 | 118 | E depois, entrar com os dados de usuário e senha. 119 | 120 | ```bash 121 | sudo mysql -u root -p 122 | ``` 123 | 124 | Em caso de usar, sem ser o root, basta executar o seguinte comando: 125 | 126 | ```bash 127 | mysql -D snippetbox -u web -p 128 | ``` 129 | 130 | Estaremos usando o driver do MySQL para Go: **[mysql](https://pkg.go.dev/github.com/go-sql-driver/mysql)** 131 | 132 | ## Shorthand single-record queries 133 | 134 | Para fazer uma query de um único registro, podemos usar o método `QueryRow()`. 135 | 136 | Exemplo: 137 | 138 | * snippets.go (método `Get()`) 139 | 140 | ```go 141 | func (m *SnippetModel) Get(id int) (Snippet, error) { 142 | var s Snippet 143 | 144 | err := m.DB.QueryRow("SELECT ...", id).Scan(&s.ID, &s.Title, &s.Content, &s.Created, &s.Expires) 145 | if err != nil { 146 | if errors.Is(err, sql.ErrNoRows) { 147 | return Snippet{}, ErrNoRecord 148 | } else { 149 | return Snippet{}, err 150 | } 151 | } 152 | 153 | return s, nil 154 | } 155 | ``` -------------------------------------------------------------------------------- /02-study/README.md: -------------------------------------------------------------------------------- 1 | # Book: Let's Go Professional Package by Alex Edwards 2 | 3 | A book dedicated to learning about the Go language for beginners and professionals. 4 | 5 | ## How to run the projects? 6 | 7 | To run the projects, you need to have the Go installed on your machine. If you don't have it, you can download it [here](https://golang.org/dl/). 8 | 9 | After installing Go, you can run the projects using the command: 10 | 11 | ```bash 12 | go run ./cmd/web 13 | ``` 14 | 15 | To download the dependencies of the project, you can use the command: 16 | 17 | ```bash 18 | go mod download 19 | ``` 20 | 21 | If you want to compile the project, you can use the command: 22 | 23 | ```bash 24 | go build .go 25 | ``` 26 | 27 | But if you want to upgrade the dependencies of the project, you can use the command: `u` to upgrade the dependencies. 28 | 29 | ```bash 30 | go get -u github.com/foo/bar 31 | ``` 32 | 33 | And if you want to see the compiled project, you can use the command: 34 | 35 | ```bash 36 | ./ 37 | ``` 38 | 39 | ## What I studied in this book? 40 | 41 | - [x] Introduction 42 | - [x] conventions 43 | - [x] About the author 44 | - [x] Copyright and disclaimer 45 | - [x] Prerequisites 46 | - [x] Background knowledge 47 | - [x] Go 1.21 48 | - [x] Other Software 49 | - [x] Foundations 50 | - [x] Project setup and creating a module 51 | - [x] Creating a module 52 | - [x] Hello World! 53 | - [x] Additional Information 54 | - [x] Module paths for downloadable packages 55 | - [x] Web Application basics 56 | - [x] Additional Information 57 | - [x] Network addresses 58 | - [x] Using `go run` 59 | - [x] Routing requests 60 | - [x] Fixed path and subtree patterns 61 | - [x] Restricting the root url pattern 62 | - [x] Additional informations 63 | - [x] Servermux features and quirks 64 | - [x] Host name matching 65 | - [x] The default servemux 66 | - [x] What about RESTful routing? 67 | - [x] Customizing HTTP headers 68 | - [x] HTTP status codes 69 | - [x] Customizing headers 70 | - [x] The `http.Error` shortcut 71 | - [x] The `net/http` constants 72 | - [x] Additional information 73 | - [x] System generated headers and content sniffing 74 | - [x] Manipulating the header map 75 | - [x] Header canonicalization 76 | - [x] Suppressing system-generated headers 77 | - [x] URL query strings 78 | - [x] The `io.writer` interface 79 | - [x] Additional information 80 | - [x] **[Golang Interfaces Explained](https://www.alexedwards.net/blog/interfaces-explained)** 81 | - [x] Project structure and organization 82 | - [x] Refactoring your existing code 83 | - [x] Additional information 84 | - [x] The internal directory 85 | - [x] HTML templating and inheritance 86 | - [x] Template composition 87 | - [x] Embedding partials 88 | - [x] Additional information 89 | - [x] The block action 90 | - [x] Serving static files 91 | - [x] The `http.FileServer` handler 92 | - [x] Using the static files 93 | - [x] Additional information 94 | - [x] File server features and functions 95 | - [x] Performance 96 | - [x] Serving single files 97 | - [x] Disabling directory listings 98 | - [x] The `http.Handler` interface 99 | - [x] Handler functions 100 | - [x] Chaining handlers 101 | - [x] Requests are handled concurrently 102 | - [ ] Configuration 103 | - [x] Managing configuration settings 104 | - [x] Command-line flags 105 | - [x] Default values 106 | - [x] Type conversions 107 | - [x] Automated help 108 | - [x] Additional information 109 | - [x] Environment variables 110 | - [x] Boolean flags 111 | - [x] Pre-existing variables 112 | - [x] Structured logging 113 | - [x] Creating a structured logger 114 | - [x] Using a structured logger 115 | - [x] Adding structured logging to our application 116 | - [x] Additional information 117 | - [x] Safer attributes 118 | - [x] JSON formatted logs 119 | - [x] Minimum log level 120 | - [x] Caller location 121 | - [x] Decoupled logging 122 | - [x] Concurrent logging 123 | - [x] Dependency injection 124 | - [x] Adding a deliberate error 125 | - [x] Additional information 126 | - [x] Closures for dependency injection 127 | - [x] Centralized error handling 128 | - [x] Revert the deliberate error 129 | - [x] Additional information 130 | - [x] Stack traces 131 | - [x] Isolating the application routes 132 | - [ ] Database-driven responses 133 | - [x] Setting up MySQL 134 | - [x] Scaffolding the database 135 | - [x] Creating a new user 136 | - [x] Test the new user 137 | - [x] Installing a database driver 138 | - [x] Modules and reproducible builds 139 | - [x] Additional information 140 | - [x] Upgrading packages 141 | - [x] Removing unused packages 142 | - [x] Creating a database connection pool 143 | - [x] Using it in our web application 144 | - [x] Testing a connection 145 | - [x] Designing a database model 146 | - [x] Using the `SnippetModel` 147 | - [x] Additional Information 148 | - [x] Benefits of this structure 149 | - [x] Executing SQL statements 150 | - [x] Executing the query 151 | - [x] Using the model in our handlers 152 | - [x] Additional information 153 | - [x] Placeholder parameters 154 | - [x] Single-record SQL queries 155 | - [x] Using the model in our handlers 156 | - [x] Additional information 157 | - [x] Checking for specific errors 158 | - [x] Shorthand single-record queries 159 | - [x] Multiple-record SQL queries 160 | - [x] Using the model in our handlers 161 | - [x] Transactions and other details 162 | - [x] The `database/sql` package 163 | - [x] Verbosity 164 | - [x] Managing null values 165 | - [x] Working with transactions 166 | - [x] Prepared statements 167 | - [ ] Dynamic HTML templates 168 | 169 | -------------------------------------------------------------------------------- /02-study/snippetbox/ui/static/css/main.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | margin: 0; 4 | padding: 0; 5 | font-size: 18px; 6 | font-family: "Ubuntu Mono", monospace; 7 | } 8 | 9 | html, body { 10 | height: 100%; 11 | } 12 | 13 | body { 14 | line-height: 1.5; 15 | background-color: #F1F3F6; 16 | color: #34495E; 17 | overflow-y: scroll; 18 | } 19 | 20 | header, nav, main, footer { 21 | padding: 2px calc((100% - 800px) / 2) 0; 22 | } 23 | 24 | main { 25 | margin-top: 54px; 26 | margin-bottom: 54px; 27 | min-height: calc(100vh - 345px); 28 | overflow: auto; 29 | } 30 | 31 | h1 a { 32 | font-size: 36px; 33 | font-weight: bold; 34 | background-image: url("/static/img/logo.png"); 35 | background-repeat: no-repeat; 36 | background-position: 0px 0px; 37 | height: 36px; 38 | padding-left: 50px; 39 | position: relative; 40 | } 41 | 42 | h1 a:hover { 43 | text-decoration: none; 44 | color: #34495E; 45 | } 46 | 47 | h2 { 48 | font-size: 22px; 49 | margin-bottom: 36px; 50 | position: relative; 51 | top: -9px; 52 | } 53 | 54 | a { 55 | color: #62CB31; 56 | text-decoration: none; 57 | } 58 | 59 | a:hover { 60 | color: #4EB722; 61 | text-decoration: underline; 62 | } 63 | 64 | textarea, input:not([type="submit"]) { 65 | font-size: 18px; 66 | font-family: "Ubuntu Mono", monospace; 67 | } 68 | 69 | header { 70 | background-image: -webkit-linear-gradient(left, #34495e, #34495e 25%, #9b59b6 25%, #9b59b6 35%, #3498db 35%, #3498db 45%, #62cb31 45%, #62cb31 55%, #ffb606 55%, #ffb606 65%, #e67e22 65%, #e67e22 75%, #e74c3c 85%, #e74c3c 85%, #c0392b 85%, #c0392b 100%); 71 | background-image: -moz-linear-gradient(left, #34495e, #34495e 25%, #9b59b6 25%, #9b59b6 35%, #3498db 35%, #3498db 45%, #62cb31 45%, #62cb31 55%, #ffb606 55%, #ffb606 65%, #e67e22 65%, #e67e22 75%, #e74c3c 85%, #e74c3c 85%, #c0392b 85%, #c0392b 100%); 72 | background-image: -ms-linear-gradient(left, #34495e, #34495e 25%, #9b59b6 25%, #9b59b6 35%, #3498db 35%, #3498db 45%, #62cb31 45%, #62cb31 55%, #ffb606 55%, #ffb606 65%, #e67e22 65%, #e67e22 75%, #e74c3c 85%, #e74c3c 85%, #c0392b 85%, #c0392b 100%); 73 | background-image: linear-gradient(to right, #34495e, #34495e 25%, #9b59b6 25%, #9b59b6 35%, #3498db 35%, #3498db 45%, #62cb31 45%, #62cb31 55%, #ffb606 55%, #ffb606 65%, #e67e22 65%, #e67e22 75%, #e74c3c 85%, #e74c3c 85%, #c0392b 85%, #c0392b 100%); 74 | background-size: 100% 6px; 75 | background-repeat: no-repeat; 76 | border-bottom: 1px solid #E4E5E7; 77 | overflow: auto; 78 | padding-top: 33px; 79 | padding-bottom: 27px; 80 | text-align: center; 81 | } 82 | 83 | header a { 84 | color: #34495E; 85 | text-decoration: none; 86 | } 87 | 88 | nav { 89 | border-bottom: 1px solid #E4E5E7; 90 | padding-top: 17px; 91 | padding-bottom: 15px; 92 | background: #F7F9FA; 93 | height: 60px; 94 | color: #6A6C6F; 95 | } 96 | 97 | nav a { 98 | margin-right: 1.5em; 99 | display: inline-block; 100 | } 101 | 102 | nav form { 103 | display: inline-block; 104 | margin-left: 1.5em; 105 | } 106 | 107 | nav div { 108 | width: 50%; 109 | float: left; 110 | } 111 | 112 | nav div:last-child { 113 | text-align: right; 114 | } 115 | 116 | nav div:last-child a { 117 | margin-left: 1.5em; 118 | margin-right: 0; 119 | } 120 | 121 | nav a.live { 122 | color: #34495E; 123 | cursor: default; 124 | } 125 | 126 | nav a.live:hover { 127 | text-decoration: none; 128 | } 129 | 130 | nav a.live:after { 131 | content: ''; 132 | display: block; 133 | position: relative; 134 | left: calc(50% - 7px); 135 | top: 9px; 136 | width: 14px; 137 | height: 14px; 138 | background: #F7F9FA; 139 | border-left: 1px solid #E4E5E7; 140 | border-bottom: 1px solid #E4E5E7; 141 | -moz-transform: rotate(45deg); 142 | -webkit-transform: rotate(-45deg); 143 | } 144 | 145 | a.button, input[type="submit"] { 146 | background-color: #62CB31; 147 | border-radius: 3px; 148 | color: #FFFFFF; 149 | padding: 18px 27px; 150 | border: none; 151 | display: inline-block; 152 | margin-top: 18px; 153 | font-weight: 700; 154 | } 155 | 156 | a.button:hover, input[type="submit"]:hover { 157 | background-color: #4EB722; 158 | color: #FFFFFF; 159 | cursor: pointer; 160 | text-decoration: none; 161 | } 162 | 163 | form div { 164 | margin-bottom: 18px; 165 | } 166 | 167 | form div:last-child { 168 | border-top: 1px dashed #E4E5E7; 169 | } 170 | 171 | form input[type="radio"] { 172 | margin-left: 18px; 173 | } 174 | 175 | form input[type="text"], form input[type="password"], form input[type="email"] { 176 | padding: 0.75em 18px; 177 | width: 100%; 178 | } 179 | 180 | form input[type=text], form input[type="password"], form input[type="email"], textarea { 181 | color: #6A6C6F; 182 | background: #FFFFFF; 183 | border: 1px solid #E4E5E7; 184 | border-radius: 3px; 185 | } 186 | 187 | form label { 188 | display: inline-block; 189 | margin-bottom: 9px; 190 | } 191 | 192 | .error { 193 | color: #C0392B; 194 | font-weight: bold; 195 | display: block; 196 | } 197 | 198 | .error + textarea, .error + input { 199 | border-color: #C0392B !important; 200 | border-width: 2px !important; 201 | } 202 | 203 | textarea { 204 | padding: 18px; 205 | width: 100%; 206 | height: 266px; 207 | } 208 | 209 | button { 210 | background: none; 211 | padding: 0; 212 | border: none; 213 | color: #62CB31; 214 | text-decoration: none; 215 | } 216 | 217 | button:hover { 218 | color: #4EB722; 219 | text-decoration: underline; 220 | cursor: pointer; 221 | } 222 | 223 | .snippet { 224 | background-color: #FFFFFF; 225 | border: 1px solid #E4E5E7; 226 | border-radius: 3px; 227 | } 228 | 229 | .snippet pre { 230 | padding: 18px; 231 | border-top: 1px solid #E4E5E7; 232 | border-bottom: 1px solid #E4E5E7; 233 | } 234 | 235 | .snippet .metadata { 236 | background-color: #F7F9FA; 237 | color: #6A6C6F; 238 | padding: 0.75em 18px; 239 | overflow: auto; 240 | } 241 | 242 | .snippet .metadata span { 243 | float: right; 244 | } 245 | 246 | .snippet .metadata strong { 247 | color: #34495E; 248 | } 249 | 250 | .snippet .metadata time { 251 | display: inline-block; 252 | } 253 | 254 | .snippet .metadata time:first-child { 255 | float: left; 256 | } 257 | 258 | .snippet .metadata time:last-child { 259 | float: right; 260 | } 261 | 262 | div.flash { 263 | color: #FFFFFF; 264 | font-weight: bold; 265 | background-color: #34495E; 266 | padding: 18px; 267 | margin-bottom: 36px; 268 | text-align: center; 269 | } 270 | 271 | div.error { 272 | color: #FFFFFF; 273 | background-color: #C0392B; 274 | padding: 18px; 275 | margin-bottom: 36px; 276 | font-weight: bold; 277 | text-align: center; 278 | } 279 | 280 | table { 281 | background: white; 282 | border: 1px solid #E4E5E7; 283 | border-collapse: collapse; 284 | width: 100%; 285 | } 286 | 287 | td, th { 288 | text-align: left; 289 | padding: 9px 18px; 290 | } 291 | 292 | th:last-child, td:last-child { 293 | text-align: right; 294 | color: #6A6C6F; 295 | } 296 | 297 | tr { 298 | border-bottom: 1px solid #E4E5E7; 299 | } 300 | 301 | tr:nth-child(2n) { 302 | background-color: #F7F9FA; 303 | } 304 | 305 | footer { 306 | border-top: 1px solid #E4E5E7; 307 | padding-top: 17px; 308 | padding-bottom: 15px; 309 | background: #F7F9FA; 310 | height: 60px; 311 | color: #6A6C6F; 312 | text-align: center; 313 | } 314 | --------------------------------------------------------------------------------