├── 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 |
18 |
19 | {{template "nav" .}}
20 |
21 |
22 | {{template "main" .}}
23 |
24 |
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 | [](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 |
--------------------------------------------------------------------------------