├── 01hello
├── go.mod
└── main.go
├── 02variables
├── go.mod
└── main.go
├── 03userinput
├── go.mod
└── main.go
├── 04conversion
├── go.mod
└── main.go
├── 05mymaths
├── go.mod
└── main.go
├── 06mytime
├── go.mod
├── main.go
├── mytime
└── mytime.exe
├── 07mypointers
├── go.mod
└── main.go
├── 08myarray
├── go.mod
└── main.go
├── 09myslices
├── go.mod
└── main.go
├── 10mymaps
├── go.mod
└── main.go
├── 11mystructs
├── go.mod
└── main.go
├── 12ifelse
├── go.mod
└── main.go
├── 13switchcase
├── go.mod
└── main.go
├── 14loops
├── go.mod
└── main.go
├── 15functions
├── go.mod
└── main.go
├── 16methods
├── go.mod
└── main.go
├── 17defer
├── go.mod
└── main.go
├── 18files
├── main.go
└── mylcogofile.txt
├── 19webrequests
├── go.mod
└── main.go
├── 20urls
├── go.mod
└── main.go
├── 21webreqverbs
├── go.mod
└── main.go
├── 22bitmorejson
├── go.mod
└── main.go
├── 23mymodules
├── go.mod
├── go.sum
├── main.go
├── mymodules
└── vendor
│ ├── github.com
│ └── gorilla
│ │ └── mux
│ │ ├── AUTHORS
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── doc.go
│ │ ├── middleware.go
│ │ ├── mux.go
│ │ ├── regexp.go
│ │ ├── route.go
│ │ └── test_helpers.go
│ └── modules.txt
├── 24buildapi
├── buildapi
├── go.mod
├── go.sum
└── main.go
├── 25mongoapi
├── controller
│ └── controller.go
├── go.mod
├── go.sum
├── main
├── main.go
├── model
│ └── models.go
└── router
│ └── router.go
├── 26goroutines
├── go.mod
└── main.go
├── 27mutexAndAwaitGroups
├── go.mod
└── main.go
├── 28channels
├── go.mod
└── main.go
├── Readme.md
├── important.txt
└── lcowebserver
├── index.js
├── package-lock.json
└── package.json
/01hello/go.mod:
--------------------------------------------------------------------------------
1 | module hello
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/01hello/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 | fmt.Println("Hello from LearnCodeonline.in")
7 | }
8 |
--------------------------------------------------------------------------------
/02variables/go.mod:
--------------------------------------------------------------------------------
1 | module variables
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/02variables/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | const LoginToken string = "ghabbhhjd" // Public
6 |
7 | func main() {
8 | var username string = "hitesh"
9 | fmt.Println(username)
10 | fmt.Printf("Variable is of type: %T \n", username)
11 |
12 | var isLoggedIn bool = false
13 | fmt.Println(isLoggedIn)
14 | fmt.Printf("Variable is of type: %T \n", isLoggedIn)
15 |
16 | var smallVal uint8 = 255
17 | fmt.Println(smallVal)
18 | fmt.Printf("Variable is of type: %T \n", smallVal)
19 |
20 | var smallFloat float64 = 255.45544511254451885
21 | fmt.Println(smallFloat)
22 | fmt.Printf("Variable is of type: %T \n", smallFloat)
23 |
24 | // default values and some aliases
25 | var anotherVariable int
26 | fmt.Println(anotherVariable)
27 | fmt.Printf("Variable is of type: %T \n", anotherVariable)
28 |
29 | // implicit type
30 |
31 | var website = "learncodeonline.in"
32 | fmt.Println(website)
33 |
34 | // no var style
35 |
36 | numberOfUser := 300000.0
37 | fmt.Println(numberOfUser)
38 |
39 | fmt.Println(LoginToken)
40 | fmt.Printf("Variable is of type: %T \n", LoginToken)
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/03userinput/go.mod:
--------------------------------------------------------------------------------
1 | module userinput
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/03userinput/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "os"
7 | )
8 |
9 | func main() {
10 | welcome := "Welcome to user input"
11 | fmt.Println(welcome)
12 |
13 | reader := bufio.NewReader(os.Stdin)
14 | fmt.Println("Enter the rating for our Pizza:")
15 |
16 | // comma ok || err err
17 |
18 | input, _ := reader.ReadString('\n')
19 | fmt.Println("Thanks for rating, ", input)
20 | fmt.Printf("Type of this rating is %T", input)
21 | }
22 |
--------------------------------------------------------------------------------
/04conversion/go.mod:
--------------------------------------------------------------------------------
1 | module conversion
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/04conversion/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "os"
7 | "strconv"
8 | "strings"
9 | )
10 |
11 | func main() {
12 | fmt.Println("Welcome to our pizza app")
13 | fmt.Println("Please rate our pizza between 1 and 5")
14 |
15 | reader := bufio.NewReader(os.Stdin)
16 |
17 | input, _ := reader.ReadString('\n')
18 |
19 | fmt.Println("Thanks for rating, ", input)
20 |
21 | numRating, err := strconv.ParseFloat(strings.TrimSpace(input), 64)
22 |
23 | if err != nil {
24 | fmt.Println(err)
25 |
26 | } else {
27 | fmt.Println("Added 1 to your rating: ", numRating+1)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/05mymaths/go.mod:
--------------------------------------------------------------------------------
1 | module mymath
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/05mymaths/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "math/big"
6 |
7 | //"math/rand"
8 | "crypto/rand"
9 | )
10 |
11 | func main() {
12 | fmt.Println("Welcome to maths in golang")
13 |
14 | //var mynumberOne int = 2
15 | //var mynumberTwo float64 = 4.5
16 |
17 | // fmt.Println("The sum is: ", mynumberOne+int(mynumberTwo))
18 |
19 | //random number
20 | // rand.Seed(time.Now().UnixNano())
21 | // fmt.Println(rand.Intn(5) + 1)
22 |
23 | //random from crypto
24 |
25 | myRandomNum, _ := rand.Int(rand.Reader, big.NewInt(5))
26 | fmt.Println(myRandomNum)
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/06mytime/go.mod:
--------------------------------------------------------------------------------
1 | module mytime
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/06mytime/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "time"
6 | )
7 |
8 | func main() {
9 | fmt.Println("Welcome to time study of golang")
10 |
11 | presentTime := time.Now()
12 | fmt.Println(presentTime)
13 |
14 | fmt.Println(presentTime.Format("01-02-2006 15:04:05 Monday"))
15 |
16 | createdDate := time.Date(2020, time.August, 12, 23, 23, 0, 0, time.UTC)
17 | fmt.Println(createdDate)
18 | fmt.Println(createdDate.Format("01-02-2006 Monday"))
19 | }
20 |
--------------------------------------------------------------------------------
/06mytime/mytime:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshchoudhary/golang/1a63628fe4bb1798a79c9319019d931e5ae179e1/06mytime/mytime
--------------------------------------------------------------------------------
/06mytime/mytime.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshchoudhary/golang/1a63628fe4bb1798a79c9319019d931e5ae179e1/06mytime/mytime.exe
--------------------------------------------------------------------------------
/07mypointers/go.mod:
--------------------------------------------------------------------------------
1 | module mypointers
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/07mypointers/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 | fmt.Println("Welcome to a class on pointers")
7 |
8 | // var ptr *int
9 | // fmt.Println("Value of pointer is ", ptr)
10 |
11 | myNumber := 23
12 |
13 | var ptr = &myNumber
14 |
15 | fmt.Println("Value of actual pointer is ", ptr)
16 | fmt.Println("Value of actual pointer is ", *ptr)
17 |
18 | *ptr = *ptr + 2
19 | fmt.Println("New value is: ", myNumber)
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/08myarray/go.mod:
--------------------------------------------------------------------------------
1 | module myarray
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/08myarray/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 | fmt.Println("Welcome to array in golangs")
7 |
8 | var fruitList [4]string
9 |
10 | fruitList[0] = "Apple"
11 | fruitList[1] = "Tomato"
12 | fruitList[3] = "Peach"
13 |
14 | fmt.Println("Fruit list is: ", fruitList)
15 | fmt.Println("Fruit list is: ", len(fruitList))
16 |
17 | var vegList = [5]string{"potato", "beans", "mushroom"}
18 | fmt.Println("Vegy list is: ", len(vegList))
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/09myslices/go.mod:
--------------------------------------------------------------------------------
1 | module slices
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/09myslices/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "sort"
6 | )
7 |
8 | func main() {
9 | fmt.Println("Welcome to video on slices")
10 |
11 | var fruitList = []string{"Apple", "Tomato", "Peach"}
12 | fmt.Printf("Type of fruitlist is %T\n", fruitList)
13 |
14 | fruitList = append(fruitList, "Mango", "Banana")
15 | fmt.Println(fruitList)
16 |
17 | fruitList = append(fruitList[:3])
18 | fmt.Println(fruitList)
19 |
20 | highScores := make([]int, 4)
21 |
22 | highScores[0] = 234
23 | highScores[1] = 945
24 | highScores[2] = 465
25 | highScores[3] = 867
26 | //highScores[4] = 777
27 |
28 | highScores = append(highScores, 555, 666, 321)
29 |
30 | fmt.Println(highScores)
31 |
32 | //fmt.Println(sort.IntsAreSorted(highScores))
33 | sort.Ints(highScores)
34 | //fmt.Println(highScores)
35 |
36 | //how to remove a value from slices based on index
37 |
38 | var courses = []string{"reactjs", "javascript", "swift", "python", "ruby"}
39 | fmt.Println(courses)
40 | var index int = 2
41 | courses = append(courses[:index], courses[index+1:]...)
42 | fmt.Println(courses)
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/10mymaps/go.mod:
--------------------------------------------------------------------------------
1 | module mymaps
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/10mymaps/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 | fmt.Println("Maps in golang")
7 |
8 | languages := make(map[string]string)
9 |
10 | languages["JS"] = "Javascript"
11 | languages["RB"] = "Ruby"
12 | languages["PY"] = "Python"
13 |
14 | fmt.Println("List of all languages: ", languages)
15 | fmt.Println("JS shorts for: ", languages["JS"])
16 |
17 | delete(languages, "RB")
18 | fmt.Println("List of all languages: ", languages)
19 |
20 | // loops are interesting in golang
21 |
22 | for _, value := range languages {
23 | fmt.Printf("For key v, value is %v\n", value)
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/11mystructs/go.mod:
--------------------------------------------------------------------------------
1 | module mystructs
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/11mystructs/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 | fmt.Println("Structs in golang")
7 | // no inheritance in golang; No super or parent
8 |
9 | hitesh := User{"Hitesh", "hitesh@go.dev", true, 16}
10 | fmt.Println(hitesh)
11 | fmt.Printf("hitesh details are: %+v\n", hitesh)
12 | fmt.Printf("Name is %v and email is %v.", hitesh.Name, hitesh.Email)
13 |
14 | }
15 |
16 | type User struct {
17 | Name string
18 | Email string
19 | Status bool
20 | Age int
21 | }
22 |
--------------------------------------------------------------------------------
/12ifelse/go.mod:
--------------------------------------------------------------------------------
1 | module ifelse
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/12ifelse/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 | fmt.Println("If else in golang")
7 |
8 | loginCount := 10
9 | var result string
10 |
11 | if loginCount < 10 {
12 | result = "Regular user"
13 | } else if loginCount > 10 {
14 | result = "Watch out"
15 | } else {
16 | result = "Exactly 10 login count"
17 | }
18 |
19 | fmt.Println(result)
20 |
21 | if 9%2 == 0 {
22 | fmt.Println("Number is even")
23 | } else {
24 | fmt.Println("Number is odd")
25 | }
26 |
27 | if num := 3; num < 10 {
28 | fmt.Println("Num is less than 10")
29 | } else {
30 | fmt.Println("Num is NOT less than 10")
31 | }
32 |
33 | // if err != nil {
34 |
35 | // }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/13switchcase/go.mod:
--------------------------------------------------------------------------------
1 | module switchcase
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/13switchcase/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "math/rand"
6 | "time"
7 | )
8 |
9 | func main() {
10 | fmt.Println("Switch and case in golang")
11 |
12 | rand.Seed(time.Now().UnixNano())
13 | diceNumber := rand.Intn(6) + 1
14 | fmt.Println("Value of dice is ", diceNumber)
15 |
16 | switch diceNumber {
17 | case 1:
18 | fmt.Println("Dice value is 1 and you can open")
19 | case 2:
20 | fmt.Println("You can move 2 spot")
21 | case 3:
22 | fmt.Println("You can move to 3 spot")
23 | fallthrough
24 | case 4:
25 | fmt.Println("you can move to 4 spot")
26 | fallthrough
27 | case 5:
28 | fmt.Println("You can move to 5 spot")
29 | case 6:
30 | fmt.Println("You can move to 6 spot and roll dice again")
31 | default:
32 | fmt.Println("What was that!")
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/14loops/go.mod:
--------------------------------------------------------------------------------
1 | module loops
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/14loops/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 | fmt.Println("Welcome to loops in golang")
7 |
8 | days := []string{"Sunday", "Tuesday", "Wednesday", "Friday", "Saturday"}
9 |
10 | fmt.Println(days)
11 |
12 | // for d := 0; d < len(days); d++ {
13 | // fmt.Println(days[d])
14 | // }
15 |
16 | // for i := range days {
17 | // fmt.Println(days[i])
18 | // }
19 |
20 | // for _, day := range days {
21 | // fmt.Printf("index is and value is %v\n", day)
22 | // }
23 |
24 | rougueValue := 1
25 |
26 | for rougueValue < 10 {
27 |
28 | if rougueValue == 2 {
29 | goto lco
30 | }
31 |
32 | if rougueValue == 5 {
33 | rougueValue++
34 | continue
35 | }
36 |
37 | fmt.Println("Value is: ", rougueValue)
38 | rougueValue++
39 | }
40 |
41 | lco:
42 | fmt.Println("Jumping at LearnCodeonline.in")
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/15functions/go.mod:
--------------------------------------------------------------------------------
1 | module functions
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/15functions/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 | fmt.Println("Welcome to functions in golang")
7 | greeter()
8 |
9 | result := adder(3, 5)
10 | fmt.Println("Result is: ", result)
11 |
12 | proRes, myMessage := proAdder(2, 5, 8, 7, 3)
13 | fmt.Println("Pro result is: ", proRes)
14 | fmt.Println("Pro Message is: ", myMessage)
15 |
16 | }
17 |
18 | func adder(valOne int, valTwo int) int {
19 | return valOne + valTwo
20 | }
21 |
22 | func proAdder(values ...int) (int, string) {
23 | total := 0
24 |
25 | for _, val := range values {
26 | total += val
27 | }
28 |
29 | return total, "Hi Pro result function"
30 |
31 | }
32 |
33 | func greeter() {
34 | fmt.Println("Namstey from golang")
35 | }
36 |
--------------------------------------------------------------------------------
/16methods/go.mod:
--------------------------------------------------------------------------------
1 | module methods
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/16methods/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 | fmt.Println("Structs in golang")
7 | // no inheritance in golang; No super or parent
8 |
9 | hitesh := User{"Hitesh", "hitesh@go.dev", true, 16}
10 | fmt.Println(hitesh)
11 | fmt.Printf("hitesh details are: %+v\n", hitesh)
12 | fmt.Printf("Name is %v and email is %v.\n", hitesh.Name, hitesh.Email)
13 | hitesh.GetStatus()
14 | hitesh.NewMail()
15 | fmt.Printf("Name is %v and email is %v.\n", hitesh.Name, hitesh.Email)
16 |
17 | }
18 |
19 | type User struct {
20 | Name string
21 | Email string
22 | Status bool
23 | Age int
24 | }
25 |
26 | func (u User) GetStatus() {
27 | fmt.Println("Is user active: ", u.Status)
28 | }
29 |
30 | func (u User) NewMail() {
31 | u.Email = "test@go.dev"
32 | fmt.Println("Email of this user is: ", u.Email)
33 | }
34 |
--------------------------------------------------------------------------------
/17defer/go.mod:
--------------------------------------------------------------------------------
1 | module defers
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/17defer/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 | defer fmt.Println("World")
7 | defer fmt.Println("One")
8 | defer fmt.Println("Two")
9 | fmt.Println("Hello")
10 | myDefer()
11 |
12 | }
13 |
14 | // world, One, Two
15 | // 0, 1, 2, 3, 4
16 | // hello, 43210, two, One, world
17 |
18 | func myDefer() {
19 | for i := 0; i < 5; i++ {
20 | defer fmt.Print(i)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/18files/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "io/ioutil"
7 | "os"
8 | )
9 |
10 | func main() {
11 | fmt.Println("Welcome to files in golang")
12 | content := "This needs to go in a file - LearnCodeOnline.in"
13 |
14 | file, err := os.Create("./mylcogofile.txt")
15 |
16 | // if err != nil {
17 | // panic(err)
18 | // }
19 | checkNilErr(err)
20 |
21 | length, err := io.WriteString(file, content)
22 | checkNilErr(err)
23 | fmt.Println("length is: ", length)
24 | defer file.Close()
25 | readFile("./mylcogofile.txt")
26 | }
27 |
28 | func readFile(filname string) {
29 | databyte, err := ioutil.ReadFile(filname)
30 | checkNilErr(err)
31 |
32 | fmt.Println("Text data inside the file is \n", string(databyte))
33 |
34 | }
35 |
36 | func checkNilErr(err error) {
37 | if err != nil {
38 | panic(err)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/18files/mylcogofile.txt:
--------------------------------------------------------------------------------
1 | This needs to go in a file - LearnCodeOnline.in
--------------------------------------------------------------------------------
/19webrequests/go.mod:
--------------------------------------------------------------------------------
1 | module lcorequest
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/19webrequests/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "io/ioutil"
6 | "net/http"
7 | )
8 |
9 | const url = "https://lco.dev"
10 |
11 | func main() {
12 | fmt.Println("LCO web request")
13 |
14 | response, err := http.Get(url)
15 |
16 | if err != nil {
17 | panic(err)
18 | }
19 |
20 | fmt.Printf("Response is of type: %T\n", response)
21 |
22 | defer response.Body.Close() // caller's responsibility to close the connection
23 |
24 | databytes, err := ioutil.ReadAll(response.Body)
25 |
26 | if err != nil {
27 | panic(err)
28 | }
29 | content := string(databytes)
30 | fmt.Println(content)
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/20urls/go.mod:
--------------------------------------------------------------------------------
1 | module lcourlweb
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/20urls/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "net/url"
6 | )
7 |
8 | const myurl string = "https://lco.dev:3000/learn?coursename=reactjs&paymentid=ghbj456ghb"
9 |
10 | func main() {
11 | fmt.Println("Welcome to handling URLs in golang")
12 | fmt.Println(myurl)
13 |
14 | //parsing
15 | result, _ := url.Parse(myurl)
16 |
17 | // fmt.Println(result.Scheme)
18 | // fmt.Println(result.Host)
19 | // fmt.Println(result.Path)
20 | // fmt.Println(result.Port())
21 | fmt.Println(result.RawQuery)
22 |
23 | qparams := result.Query()
24 | fmt.Printf("The type of query params are: %T\n", qparams)
25 |
26 | fmt.Println(qparams["coursename"])
27 |
28 | for _, val := range qparams {
29 | fmt.Println("Param is: ", val)
30 | }
31 |
32 | partsOfUrl := &url.URL{
33 | Scheme: "https",
34 | Host: "lco.dev",
35 | Path: "/tutcss",
36 | RawPath: "user=hitesh",
37 | }
38 |
39 | anotherURL := partsOfUrl.String()
40 | fmt.Println(anotherURL)
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/21webreqverbs/go.mod:
--------------------------------------------------------------------------------
1 | module webverbs
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/21webreqverbs/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "io/ioutil"
6 | "net/http"
7 | "net/url"
8 | "strings"
9 | )
10 |
11 | func main() {
12 | fmt.Println("Welcome to web verb video - LCO")
13 | //PerformGetRequest()
14 | // PerformPostJsonRequest()
15 | PerformPostFormRequest()
16 | }
17 |
18 | func PerformGetRequest() {
19 | const myurl = "http://localhost:8000/get"
20 |
21 | response, err := http.Get(myurl)
22 | if err != nil {
23 | panic(err)
24 | }
25 |
26 | defer response.Body.Close()
27 |
28 | fmt.Println("Status code: ", response.StatusCode)
29 | fmt.Println("Content length is: ", response.ContentLength)
30 |
31 | var responseString strings.Builder
32 | content, _ := ioutil.ReadAll(response.Body)
33 | byteCount, _ := responseString.Write(content)
34 |
35 | fmt.Println("ByteCount is: ", byteCount)
36 | fmt.Println(responseString.String())
37 |
38 | //fmt.Println(content)
39 | //fmt.Println(string(content))
40 | }
41 |
42 | func PerformPostJsonRequest() {
43 | const myurl = "http://localhost:8000/post"
44 |
45 | //fake json payload
46 |
47 | requestBody := strings.NewReader(`
48 | {
49 | "coursename":"Let's go with golang",
50 | "price": 0,
51 | "platform":"learnCodeOnline.in"
52 | }
53 | `)
54 |
55 | response, err := http.Post(myurl, "application/json", requestBody)
56 |
57 | if err != nil {
58 | panic(err)
59 | }
60 | defer response.Body.Close()
61 |
62 | content, _ := ioutil.ReadAll(response.Body)
63 |
64 | fmt.Println(string(content))
65 | }
66 |
67 | func PerformPostFormRequest() {
68 | const myurl = "http://localhost:8000/postform"
69 |
70 | //formdata
71 |
72 | data := url.Values{}
73 | data.Add("firstname", "hitesh")
74 | data.Add("lastname", "choudhary")
75 | data.Add("email", "hitesh@go.dev")
76 |
77 | response, err := http.PostForm(myurl, data)
78 | if err != nil {
79 | panic(err)
80 | }
81 |
82 | defer response.Body.Close()
83 |
84 | content, _ := ioutil.ReadAll(response.Body)
85 | fmt.Println(string(content))
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/22bitmorejson/go.mod:
--------------------------------------------------------------------------------
1 | module myjson
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/22bitmorejson/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | )
7 |
8 | type course struct {
9 | Name string `json:"coursename"`
10 | Price int
11 | Platform string `json:"website"`
12 | Password string `json:"-"`
13 | Tags []string `json:"tags,omitempty"`
14 | }
15 |
16 | func main() {
17 | fmt.Println("Welcome to JSON video")
18 | // EncodeJson()
19 | DecodeJson()
20 | }
21 |
22 | func EncodeJson() {
23 |
24 | lcoCourses := []course{
25 | {"ReactJS Bootcamp", 299, "LearnCodeOnline.in", "abc123", []string{"web-dev", "js"}},
26 | {"MERN Bootcamp", 199, "LearnCodeOnline.in", "bcd123", []string{"full-stack", "js"}},
27 | {"Angular Bootcamp", 299, "LearnCodeOnline.in", "hit123", nil},
28 | }
29 |
30 | //package this data as JSON data
31 |
32 | finalJson, err := json.MarshalIndent(lcoCourses, "", "\t")
33 | if err != nil {
34 | panic(err)
35 | }
36 | fmt.Printf("%s\n", finalJson)
37 |
38 | }
39 |
40 | func DecodeJson() {
41 | jsonDataFromWeb := []byte(`
42 | {
43 | "coursename": "ReactJS Bootcamp",
44 | "Price": 299,
45 | "website": "LearnCodeOnline.in",
46 | "tags": ["web-dev","js"]
47 | }
48 | `)
49 |
50 | var lcoCourse course
51 |
52 | checkValid := json.Valid(jsonDataFromWeb)
53 |
54 | if checkValid {
55 | fmt.Println("JSON was valid")
56 | json.Unmarshal(jsonDataFromWeb, &lcoCourse)
57 | fmt.Printf("%#v\n", lcoCourse)
58 | } else {
59 | fmt.Println("JSON WAS NOT VALID")
60 | }
61 |
62 | // some cases where you just want to add data to key value
63 |
64 | var myOnlineData map[string]interface{}
65 | json.Unmarshal(jsonDataFromWeb, &myOnlineData)
66 | fmt.Printf("%#v\n", myOnlineData)
67 |
68 | for k, v := range myOnlineData {
69 | fmt.Printf("Key is %v and value is %v and Type is: %T\n", k, v, v)
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/23mymodules/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/hiteshchoudhary/mymodules
2 |
3 | go 1.17
4 |
5 | require github.com/gorilla/mux v1.8.0
6 |
--------------------------------------------------------------------------------
/23mymodules/go.sum:
--------------------------------------------------------------------------------
1 | github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
2 | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
3 |
--------------------------------------------------------------------------------
/23mymodules/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 |
8 | "github.com/gorilla/mux"
9 | )
10 |
11 | func main() {
12 | fmt.Println("Hello mod in golang")
13 | greeter()
14 | r := mux.NewRouter()
15 | r.HandleFunc("/", serveHome).Methods("GET")
16 |
17 | log.Fatal(http.ListenAndServe(":4000", r))
18 | }
19 |
20 | func greeter() {
21 | fmt.Println("Hey there mod users")
22 | }
23 |
24 | func serveHome(w http.ResponseWriter, r *http.Request) {
25 | w.Write([]byte("
Welcome to golang series on YT
"))
26 | }
27 |
--------------------------------------------------------------------------------
/23mymodules/mymodules:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshchoudhary/golang/1a63628fe4bb1798a79c9319019d931e5ae179e1/23mymodules/mymodules
--------------------------------------------------------------------------------
/23mymodules/vendor/github.com/gorilla/mux/AUTHORS:
--------------------------------------------------------------------------------
1 | # This is the official list of gorilla/mux authors for copyright purposes.
2 | #
3 | # Please keep the list sorted.
4 |
5 | Google LLC (https://opensource.google.com/)
6 | Kamil Kisielk
7 | Matt Silverlock
8 | Rodrigo Moraes (https://github.com/moraes)
9 |
--------------------------------------------------------------------------------
/23mymodules/vendor/github.com/gorilla/mux/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012-2018 The Gorilla Authors. All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are
5 | met:
6 |
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above
10 | copyright notice, this list of conditions and the following disclaimer
11 | in the documentation and/or other materials provided with the
12 | distribution.
13 | * Neither the name of Google Inc. nor the names of its
14 | contributors may be used to endorse or promote products derived from
15 | this software without specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/23mymodules/vendor/github.com/gorilla/mux/README.md:
--------------------------------------------------------------------------------
1 | # gorilla/mux
2 |
3 | [](https://godoc.org/github.com/gorilla/mux)
4 | [](https://circleci.com/gh/gorilla/mux)
5 | [](https://sourcegraph.com/github.com/gorilla/mux?badge)
6 |
7 | 
8 |
9 | https://www.gorillatoolkit.org/pkg/mux
10 |
11 | Package `gorilla/mux` implements a request router and dispatcher for matching incoming requests to
12 | their respective handler.
13 |
14 | The name mux stands for "HTTP request multiplexer". Like the standard `http.ServeMux`, `mux.Router` matches incoming requests against a list of registered routes and calls a handler for the route that matches the URL or other conditions. The main features are:
15 |
16 | * It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`.
17 | * Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers.
18 | * URL hosts, paths and query values can have variables with an optional regular expression.
19 | * Registered URLs can be built, or "reversed", which helps maintaining references to resources.
20 | * Routes can be used as subrouters: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching.
21 |
22 | ---
23 |
24 | * [Install](#install)
25 | * [Examples](#examples)
26 | * [Matching Routes](#matching-routes)
27 | * [Static Files](#static-files)
28 | * [Serving Single Page Applications](#serving-single-page-applications) (e.g. React, Vue, Ember.js, etc.)
29 | * [Registered URLs](#registered-urls)
30 | * [Walking Routes](#walking-routes)
31 | * [Graceful Shutdown](#graceful-shutdown)
32 | * [Middleware](#middleware)
33 | * [Handling CORS Requests](#handling-cors-requests)
34 | * [Testing Handlers](#testing-handlers)
35 | * [Full Example](#full-example)
36 |
37 | ---
38 |
39 | ## Install
40 |
41 | With a [correctly configured](https://golang.org/doc/install#testing) Go toolchain:
42 |
43 | ```sh
44 | go get -u github.com/gorilla/mux
45 | ```
46 |
47 | ## Examples
48 |
49 | Let's start registering a couple of URL paths and handlers:
50 |
51 | ```go
52 | func main() {
53 | r := mux.NewRouter()
54 | r.HandleFunc("/", HomeHandler)
55 | r.HandleFunc("/products", ProductsHandler)
56 | r.HandleFunc("/articles", ArticlesHandler)
57 | http.Handle("/", r)
58 | }
59 | ```
60 |
61 | Here we register three routes mapping URL paths to handlers. This is equivalent to how `http.HandleFunc()` works: if an incoming request URL matches one of the paths, the corresponding handler is called passing (`http.ResponseWriter`, `*http.Request`) as parameters.
62 |
63 | Paths can have variables. They are defined using the format `{name}` or `{name:pattern}`. If a regular expression pattern is not defined, the matched variable will be anything until the next slash. For example:
64 |
65 | ```go
66 | r := mux.NewRouter()
67 | r.HandleFunc("/products/{key}", ProductHandler)
68 | r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
69 | r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
70 | ```
71 |
72 | The names are used to create a map of route variables which can be retrieved calling `mux.Vars()`:
73 |
74 | ```go
75 | func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) {
76 | vars := mux.Vars(r)
77 | w.WriteHeader(http.StatusOK)
78 | fmt.Fprintf(w, "Category: %v\n", vars["category"])
79 | }
80 | ```
81 |
82 | And this is all you need to know about the basic usage. More advanced options are explained below.
83 |
84 | ### Matching Routes
85 |
86 | Routes can also be restricted to a domain or subdomain. Just define a host pattern to be matched. They can also have variables:
87 |
88 | ```go
89 | r := mux.NewRouter()
90 | // Only matches if domain is "www.example.com".
91 | r.Host("www.example.com")
92 | // Matches a dynamic subdomain.
93 | r.Host("{subdomain:[a-z]+}.example.com")
94 | ```
95 |
96 | There are several other matchers that can be added. To match path prefixes:
97 |
98 | ```go
99 | r.PathPrefix("/products/")
100 | ```
101 |
102 | ...or HTTP methods:
103 |
104 | ```go
105 | r.Methods("GET", "POST")
106 | ```
107 |
108 | ...or URL schemes:
109 |
110 | ```go
111 | r.Schemes("https")
112 | ```
113 |
114 | ...or header values:
115 |
116 | ```go
117 | r.Headers("X-Requested-With", "XMLHttpRequest")
118 | ```
119 |
120 | ...or query values:
121 |
122 | ```go
123 | r.Queries("key", "value")
124 | ```
125 |
126 | ...or to use a custom matcher function:
127 |
128 | ```go
129 | r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
130 | return r.ProtoMajor == 0
131 | })
132 | ```
133 |
134 | ...and finally, it is possible to combine several matchers in a single route:
135 |
136 | ```go
137 | r.HandleFunc("/products", ProductsHandler).
138 | Host("www.example.com").
139 | Methods("GET").
140 | Schemes("http")
141 | ```
142 |
143 | Routes are tested in the order they were added to the router. If two routes match, the first one wins:
144 |
145 | ```go
146 | r := mux.NewRouter()
147 | r.HandleFunc("/specific", specificHandler)
148 | r.PathPrefix("/").Handler(catchAllHandler)
149 | ```
150 |
151 | Setting the same matching conditions again and again can be boring, so we have a way to group several routes that share the same requirements. We call it "subrouting".
152 |
153 | For example, let's say we have several URLs that should only match when the host is `www.example.com`. Create a route for that host and get a "subrouter" from it:
154 |
155 | ```go
156 | r := mux.NewRouter()
157 | s := r.Host("www.example.com").Subrouter()
158 | ```
159 |
160 | Then register routes in the subrouter:
161 |
162 | ```go
163 | s.HandleFunc("/products/", ProductsHandler)
164 | s.HandleFunc("/products/{key}", ProductHandler)
165 | s.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
166 | ```
167 |
168 | The three URL paths we registered above will only be tested if the domain is `www.example.com`, because the subrouter is tested first. This is not only convenient, but also optimizes request matching. You can create subrouters combining any attribute matchers accepted by a route.
169 |
170 | Subrouters can be used to create domain or path "namespaces": you define subrouters in a central place and then parts of the app can register its paths relatively to a given subrouter.
171 |
172 | There's one more thing about subroutes. When a subrouter has a path prefix, the inner routes use it as base for their paths:
173 |
174 | ```go
175 | r := mux.NewRouter()
176 | s := r.PathPrefix("/products").Subrouter()
177 | // "/products/"
178 | s.HandleFunc("/", ProductsHandler)
179 | // "/products/{key}/"
180 | s.HandleFunc("/{key}/", ProductHandler)
181 | // "/products/{key}/details"
182 | s.HandleFunc("/{key}/details", ProductDetailsHandler)
183 | ```
184 |
185 |
186 | ### Static Files
187 |
188 | Note that the path provided to `PathPrefix()` represents a "wildcard": calling
189 | `PathPrefix("/static/").Handler(...)` means that the handler will be passed any
190 | request that matches "/static/\*". This makes it easy to serve static files with mux:
191 |
192 | ```go
193 | func main() {
194 | var dir string
195 |
196 | flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
197 | flag.Parse()
198 | r := mux.NewRouter()
199 |
200 | // This will serve files under http://localhost:8000/static/
201 | r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
202 |
203 | srv := &http.Server{
204 | Handler: r,
205 | Addr: "127.0.0.1:8000",
206 | // Good practice: enforce timeouts for servers you create!
207 | WriteTimeout: 15 * time.Second,
208 | ReadTimeout: 15 * time.Second,
209 | }
210 |
211 | log.Fatal(srv.ListenAndServe())
212 | }
213 | ```
214 |
215 | ### Serving Single Page Applications
216 |
217 | Most of the time it makes sense to serve your SPA on a separate web server from your API,
218 | but sometimes it's desirable to serve them both from one place. It's possible to write a simple
219 | handler for serving your SPA (for use with React Router's [BrowserRouter](https://reacttraining.com/react-router/web/api/BrowserRouter) for example), and leverage
220 | mux's powerful routing for your API endpoints.
221 |
222 | ```go
223 | package main
224 |
225 | import (
226 | "encoding/json"
227 | "log"
228 | "net/http"
229 | "os"
230 | "path/filepath"
231 | "time"
232 |
233 | "github.com/gorilla/mux"
234 | )
235 |
236 | // spaHandler implements the http.Handler interface, so we can use it
237 | // to respond to HTTP requests. The path to the static directory and
238 | // path to the index file within that static directory are used to
239 | // serve the SPA in the given static directory.
240 | type spaHandler struct {
241 | staticPath string
242 | indexPath string
243 | }
244 |
245 | // ServeHTTP inspects the URL path to locate a file within the static dir
246 | // on the SPA handler. If a file is found, it will be served. If not, the
247 | // file located at the index path on the SPA handler will be served. This
248 | // is suitable behavior for serving an SPA (single page application).
249 | func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
250 | // get the absolute path to prevent directory traversal
251 | path, err := filepath.Abs(r.URL.Path)
252 | if err != nil {
253 | // if we failed to get the absolute path respond with a 400 bad request
254 | // and stop
255 | http.Error(w, err.Error(), http.StatusBadRequest)
256 | return
257 | }
258 |
259 | // prepend the path with the path to the static directory
260 | path = filepath.Join(h.staticPath, path)
261 |
262 | // check whether a file exists at the given path
263 | _, err = os.Stat(path)
264 | if os.IsNotExist(err) {
265 | // file does not exist, serve index.html
266 | http.ServeFile(w, r, filepath.Join(h.staticPath, h.indexPath))
267 | return
268 | } else if err != nil {
269 | // if we got an error (that wasn't that the file doesn't exist) stating the
270 | // file, return a 500 internal server error and stop
271 | http.Error(w, err.Error(), http.StatusInternalServerError)
272 | return
273 | }
274 |
275 | // otherwise, use http.FileServer to serve the static dir
276 | http.FileServer(http.Dir(h.staticPath)).ServeHTTP(w, r)
277 | }
278 |
279 | func main() {
280 | router := mux.NewRouter()
281 |
282 | router.HandleFunc("/api/health", func(w http.ResponseWriter, r *http.Request) {
283 | // an example API handler
284 | json.NewEncoder(w).Encode(map[string]bool{"ok": true})
285 | })
286 |
287 | spa := spaHandler{staticPath: "build", indexPath: "index.html"}
288 | router.PathPrefix("/").Handler(spa)
289 |
290 | srv := &http.Server{
291 | Handler: router,
292 | Addr: "127.0.0.1:8000",
293 | // Good practice: enforce timeouts for servers you create!
294 | WriteTimeout: 15 * time.Second,
295 | ReadTimeout: 15 * time.Second,
296 | }
297 |
298 | log.Fatal(srv.ListenAndServe())
299 | }
300 | ```
301 |
302 | ### Registered URLs
303 |
304 | Now let's see how to build registered URLs.
305 |
306 | Routes can be named. All routes that define a name can have their URLs built, or "reversed". We define a name calling `Name()` on a route. For example:
307 |
308 | ```go
309 | r := mux.NewRouter()
310 | r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
311 | Name("article")
312 | ```
313 |
314 | To build a URL, get the route and call the `URL()` method, passing a sequence of key/value pairs for the route variables. For the previous route, we would do:
315 |
316 | ```go
317 | url, err := r.Get("article").URL("category", "technology", "id", "42")
318 | ```
319 |
320 | ...and the result will be a `url.URL` with the following path:
321 |
322 | ```
323 | "/articles/technology/42"
324 | ```
325 |
326 | This also works for host and query value variables:
327 |
328 | ```go
329 | r := mux.NewRouter()
330 | r.Host("{subdomain}.example.com").
331 | Path("/articles/{category}/{id:[0-9]+}").
332 | Queries("filter", "{filter}").
333 | HandlerFunc(ArticleHandler).
334 | Name("article")
335 |
336 | // url.String() will be "http://news.example.com/articles/technology/42?filter=gorilla"
337 | url, err := r.Get("article").URL("subdomain", "news",
338 | "category", "technology",
339 | "id", "42",
340 | "filter", "gorilla")
341 | ```
342 |
343 | All variables defined in the route are required, and their values must conform to the corresponding patterns. These requirements guarantee that a generated URL will always match a registered route -- the only exception is for explicitly defined "build-only" routes which never match.
344 |
345 | Regex support also exists for matching Headers within a route. For example, we could do:
346 |
347 | ```go
348 | r.HeadersRegexp("Content-Type", "application/(text|json)")
349 | ```
350 |
351 | ...and the route will match both requests with a Content-Type of `application/json` as well as `application/text`
352 |
353 | There's also a way to build only the URL host or path for a route: use the methods `URLHost()` or `URLPath()` instead. For the previous route, we would do:
354 |
355 | ```go
356 | // "http://news.example.com/"
357 | host, err := r.Get("article").URLHost("subdomain", "news")
358 |
359 | // "/articles/technology/42"
360 | path, err := r.Get("article").URLPath("category", "technology", "id", "42")
361 | ```
362 |
363 | And if you use subrouters, host and path defined separately can be built as well:
364 |
365 | ```go
366 | r := mux.NewRouter()
367 | s := r.Host("{subdomain}.example.com").Subrouter()
368 | s.Path("/articles/{category}/{id:[0-9]+}").
369 | HandlerFunc(ArticleHandler).
370 | Name("article")
371 |
372 | // "http://news.example.com/articles/technology/42"
373 | url, err := r.Get("article").URL("subdomain", "news",
374 | "category", "technology",
375 | "id", "42")
376 | ```
377 |
378 | ### Walking Routes
379 |
380 | The `Walk` function on `mux.Router` can be used to visit all of the routes that are registered on a router. For example,
381 | the following prints all of the registered routes:
382 |
383 | ```go
384 | package main
385 |
386 | import (
387 | "fmt"
388 | "net/http"
389 | "strings"
390 |
391 | "github.com/gorilla/mux"
392 | )
393 |
394 | func handler(w http.ResponseWriter, r *http.Request) {
395 | return
396 | }
397 |
398 | func main() {
399 | r := mux.NewRouter()
400 | r.HandleFunc("/", handler)
401 | r.HandleFunc("/products", handler).Methods("POST")
402 | r.HandleFunc("/articles", handler).Methods("GET")
403 | r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
404 | r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
405 | err := r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
406 | pathTemplate, err := route.GetPathTemplate()
407 | if err == nil {
408 | fmt.Println("ROUTE:", pathTemplate)
409 | }
410 | pathRegexp, err := route.GetPathRegexp()
411 | if err == nil {
412 | fmt.Println("Path regexp:", pathRegexp)
413 | }
414 | queriesTemplates, err := route.GetQueriesTemplates()
415 | if err == nil {
416 | fmt.Println("Queries templates:", strings.Join(queriesTemplates, ","))
417 | }
418 | queriesRegexps, err := route.GetQueriesRegexp()
419 | if err == nil {
420 | fmt.Println("Queries regexps:", strings.Join(queriesRegexps, ","))
421 | }
422 | methods, err := route.GetMethods()
423 | if err == nil {
424 | fmt.Println("Methods:", strings.Join(methods, ","))
425 | }
426 | fmt.Println()
427 | return nil
428 | })
429 |
430 | if err != nil {
431 | fmt.Println(err)
432 | }
433 |
434 | http.Handle("/", r)
435 | }
436 | ```
437 |
438 | ### Graceful Shutdown
439 |
440 | Go 1.8 introduced the ability to [gracefully shutdown](https://golang.org/doc/go1.8#http_shutdown) a `*http.Server`. Here's how to do that alongside `mux`:
441 |
442 | ```go
443 | package main
444 |
445 | import (
446 | "context"
447 | "flag"
448 | "log"
449 | "net/http"
450 | "os"
451 | "os/signal"
452 | "time"
453 |
454 | "github.com/gorilla/mux"
455 | )
456 |
457 | func main() {
458 | var wait time.Duration
459 | flag.DurationVar(&wait, "graceful-timeout", time.Second * 15, "the duration for which the server gracefully wait for existing connections to finish - e.g. 15s or 1m")
460 | flag.Parse()
461 |
462 | r := mux.NewRouter()
463 | // Add your routes as needed
464 |
465 | srv := &http.Server{
466 | Addr: "0.0.0.0:8080",
467 | // Good practice to set timeouts to avoid Slowloris attacks.
468 | WriteTimeout: time.Second * 15,
469 | ReadTimeout: time.Second * 15,
470 | IdleTimeout: time.Second * 60,
471 | Handler: r, // Pass our instance of gorilla/mux in.
472 | }
473 |
474 | // Run our server in a goroutine so that it doesn't block.
475 | go func() {
476 | if err := srv.ListenAndServe(); err != nil {
477 | log.Println(err)
478 | }
479 | }()
480 |
481 | c := make(chan os.Signal, 1)
482 | // We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C)
483 | // SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught.
484 | signal.Notify(c, os.Interrupt)
485 |
486 | // Block until we receive our signal.
487 | <-c
488 |
489 | // Create a deadline to wait for.
490 | ctx, cancel := context.WithTimeout(context.Background(), wait)
491 | defer cancel()
492 | // Doesn't block if no connections, but will otherwise wait
493 | // until the timeout deadline.
494 | srv.Shutdown(ctx)
495 | // Optionally, you could run srv.Shutdown in a goroutine and block on
496 | // <-ctx.Done() if your application should wait for other services
497 | // to finalize based on context cancellation.
498 | log.Println("shutting down")
499 | os.Exit(0)
500 | }
501 | ```
502 |
503 | ### Middleware
504 |
505 | Mux supports the addition of middlewares to a [Router](https://godoc.org/github.com/gorilla/mux#Router), which are executed in the order they are added if a match is found, including its subrouters.
506 | Middlewares are (typically) small pieces of code which take one request, do something with it, and pass it down to another middleware or the final handler. Some common use cases for middleware are request logging, header manipulation, or `ResponseWriter` hijacking.
507 |
508 | Mux middlewares are defined using the de facto standard type:
509 |
510 | ```go
511 | type MiddlewareFunc func(http.Handler) http.Handler
512 | ```
513 |
514 | Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc. This takes advantage of closures being able access variables from the context where they are created, while retaining the signature enforced by the receivers.
515 |
516 | A very basic middleware which logs the URI of the request being handled could be written as:
517 |
518 | ```go
519 | func loggingMiddleware(next http.Handler) http.Handler {
520 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
521 | // Do stuff here
522 | log.Println(r.RequestURI)
523 | // Call the next handler, which can be another middleware in the chain, or the final handler.
524 | next.ServeHTTP(w, r)
525 | })
526 | }
527 | ```
528 |
529 | Middlewares can be added to a router using `Router.Use()`:
530 |
531 | ```go
532 | r := mux.NewRouter()
533 | r.HandleFunc("/", handler)
534 | r.Use(loggingMiddleware)
535 | ```
536 |
537 | A more complex authentication middleware, which maps session token to users, could be written as:
538 |
539 | ```go
540 | // Define our struct
541 | type authenticationMiddleware struct {
542 | tokenUsers map[string]string
543 | }
544 |
545 | // Initialize it somewhere
546 | func (amw *authenticationMiddleware) Populate() {
547 | amw.tokenUsers["00000000"] = "user0"
548 | amw.tokenUsers["aaaaaaaa"] = "userA"
549 | amw.tokenUsers["05f717e5"] = "randomUser"
550 | amw.tokenUsers["deadbeef"] = "user0"
551 | }
552 |
553 | // Middleware function, which will be called for each request
554 | func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
555 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
556 | token := r.Header.Get("X-Session-Token")
557 |
558 | if user, found := amw.tokenUsers[token]; found {
559 | // We found the token in our map
560 | log.Printf("Authenticated user %s\n", user)
561 | // Pass down the request to the next middleware (or final handler)
562 | next.ServeHTTP(w, r)
563 | } else {
564 | // Write an error and stop the handler chain
565 | http.Error(w, "Forbidden", http.StatusForbidden)
566 | }
567 | })
568 | }
569 | ```
570 |
571 | ```go
572 | r := mux.NewRouter()
573 | r.HandleFunc("/", handler)
574 |
575 | amw := authenticationMiddleware{}
576 | amw.Populate()
577 |
578 | r.Use(amw.Middleware)
579 | ```
580 |
581 | Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. Middlewares _should_ write to `ResponseWriter` if they _are_ going to terminate the request, and they _should not_ write to `ResponseWriter` if they _are not_ going to terminate it.
582 |
583 | ### Handling CORS Requests
584 |
585 | [CORSMethodMiddleware](https://godoc.org/github.com/gorilla/mux#CORSMethodMiddleware) intends to make it easier to strictly set the `Access-Control-Allow-Methods` response header.
586 |
587 | * You will still need to use your own CORS handler to set the other CORS headers such as `Access-Control-Allow-Origin`
588 | * The middleware will set the `Access-Control-Allow-Methods` header to all the method matchers (e.g. `r.Methods(http.MethodGet, http.MethodPut, http.MethodOptions)` -> `Access-Control-Allow-Methods: GET,PUT,OPTIONS`) on a route
589 | * If you do not specify any methods, then:
590 | > _Important_: there must be an `OPTIONS` method matcher for the middleware to set the headers.
591 |
592 | Here is an example of using `CORSMethodMiddleware` along with a custom `OPTIONS` handler to set all the required CORS headers:
593 |
594 | ```go
595 | package main
596 |
597 | import (
598 | "net/http"
599 | "github.com/gorilla/mux"
600 | )
601 |
602 | func main() {
603 | r := mux.NewRouter()
604 |
605 | // IMPORTANT: you must specify an OPTIONS method matcher for the middleware to set CORS headers
606 | r.HandleFunc("/foo", fooHandler).Methods(http.MethodGet, http.MethodPut, http.MethodPatch, http.MethodOptions)
607 | r.Use(mux.CORSMethodMiddleware(r))
608 |
609 | http.ListenAndServe(":8080", r)
610 | }
611 |
612 | func fooHandler(w http.ResponseWriter, r *http.Request) {
613 | w.Header().Set("Access-Control-Allow-Origin", "*")
614 | if r.Method == http.MethodOptions {
615 | return
616 | }
617 |
618 | w.Write([]byte("foo"))
619 | }
620 | ```
621 |
622 | And an request to `/foo` using something like:
623 |
624 | ```bash
625 | curl localhost:8080/foo -v
626 | ```
627 |
628 | Would look like:
629 |
630 | ```bash
631 | * Trying ::1...
632 | * TCP_NODELAY set
633 | * Connected to localhost (::1) port 8080 (#0)
634 | > GET /foo HTTP/1.1
635 | > Host: localhost:8080
636 | > User-Agent: curl/7.59.0
637 | > Accept: */*
638 | >
639 | < HTTP/1.1 200 OK
640 | < Access-Control-Allow-Methods: GET,PUT,PATCH,OPTIONS
641 | < Access-Control-Allow-Origin: *
642 | < Date: Fri, 28 Jun 2019 20:13:30 GMT
643 | < Content-Length: 3
644 | < Content-Type: text/plain; charset=utf-8
645 | <
646 | * Connection #0 to host localhost left intact
647 | foo
648 | ```
649 |
650 | ### Testing Handlers
651 |
652 | Testing handlers in a Go web application is straightforward, and _mux_ doesn't complicate this any further. Given two files: `endpoints.go` and `endpoints_test.go`, here's how we'd test an application using _mux_.
653 |
654 | First, our simple HTTP handler:
655 |
656 | ```go
657 | // endpoints.go
658 | package main
659 |
660 | func HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
661 | // A very simple health check.
662 | w.Header().Set("Content-Type", "application/json")
663 | w.WriteHeader(http.StatusOK)
664 |
665 | // In the future we could report back on the status of our DB, or our cache
666 | // (e.g. Redis) by performing a simple PING, and include them in the response.
667 | io.WriteString(w, `{"alive": true}`)
668 | }
669 |
670 | func main() {
671 | r := mux.NewRouter()
672 | r.HandleFunc("/health", HealthCheckHandler)
673 |
674 | log.Fatal(http.ListenAndServe("localhost:8080", r))
675 | }
676 | ```
677 |
678 | Our test code:
679 |
680 | ```go
681 | // endpoints_test.go
682 | package main
683 |
684 | import (
685 | "net/http"
686 | "net/http/httptest"
687 | "testing"
688 | )
689 |
690 | func TestHealthCheckHandler(t *testing.T) {
691 | // Create a request to pass to our handler. We don't have any query parameters for now, so we'll
692 | // pass 'nil' as the third parameter.
693 | req, err := http.NewRequest("GET", "/health", nil)
694 | if err != nil {
695 | t.Fatal(err)
696 | }
697 |
698 | // We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response.
699 | rr := httptest.NewRecorder()
700 | handler := http.HandlerFunc(HealthCheckHandler)
701 |
702 | // Our handlers satisfy http.Handler, so we can call their ServeHTTP method
703 | // directly and pass in our Request and ResponseRecorder.
704 | handler.ServeHTTP(rr, req)
705 |
706 | // Check the status code is what we expect.
707 | if status := rr.Code; status != http.StatusOK {
708 | t.Errorf("handler returned wrong status code: got %v want %v",
709 | status, http.StatusOK)
710 | }
711 |
712 | // Check the response body is what we expect.
713 | expected := `{"alive": true}`
714 | if rr.Body.String() != expected {
715 | t.Errorf("handler returned unexpected body: got %v want %v",
716 | rr.Body.String(), expected)
717 | }
718 | }
719 | ```
720 |
721 | In the case that our routes have [variables](#examples), we can pass those in the request. We could write
722 | [table-driven tests](https://dave.cheney.net/2013/06/09/writing-table-driven-tests-in-go) to test multiple
723 | possible route variables as needed.
724 |
725 | ```go
726 | // endpoints.go
727 | func main() {
728 | r := mux.NewRouter()
729 | // A route with a route variable:
730 | r.HandleFunc("/metrics/{type}", MetricsHandler)
731 |
732 | log.Fatal(http.ListenAndServe("localhost:8080", r))
733 | }
734 | ```
735 |
736 | Our test file, with a table-driven test of `routeVariables`:
737 |
738 | ```go
739 | // endpoints_test.go
740 | func TestMetricsHandler(t *testing.T) {
741 | tt := []struct{
742 | routeVariable string
743 | shouldPass bool
744 | }{
745 | {"goroutines", true},
746 | {"heap", true},
747 | {"counters", true},
748 | {"queries", true},
749 | {"adhadaeqm3k", false},
750 | }
751 |
752 | for _, tc := range tt {
753 | path := fmt.Sprintf("/metrics/%s", tc.routeVariable)
754 | req, err := http.NewRequest("GET", path, nil)
755 | if err != nil {
756 | t.Fatal(err)
757 | }
758 |
759 | rr := httptest.NewRecorder()
760 |
761 | // Need to create a router that we can pass the request through so that the vars will be added to the context
762 | router := mux.NewRouter()
763 | router.HandleFunc("/metrics/{type}", MetricsHandler)
764 | router.ServeHTTP(rr, req)
765 |
766 | // In this case, our MetricsHandler returns a non-200 response
767 | // for a route variable it doesn't know about.
768 | if rr.Code == http.StatusOK && !tc.shouldPass {
769 | t.Errorf("handler should have failed on routeVariable %s: got %v want %v",
770 | tc.routeVariable, rr.Code, http.StatusOK)
771 | }
772 | }
773 | }
774 | ```
775 |
776 | ## Full Example
777 |
778 | Here's a complete, runnable example of a small `mux` based server:
779 |
780 | ```go
781 | package main
782 |
783 | import (
784 | "net/http"
785 | "log"
786 | "github.com/gorilla/mux"
787 | )
788 |
789 | func YourHandler(w http.ResponseWriter, r *http.Request) {
790 | w.Write([]byte("Gorilla!\n"))
791 | }
792 |
793 | func main() {
794 | r := mux.NewRouter()
795 | // Routes consist of a path and a handler function.
796 | r.HandleFunc("/", YourHandler)
797 |
798 | // Bind to a port and pass our router in
799 | log.Fatal(http.ListenAndServe(":8000", r))
800 | }
801 | ```
802 |
803 | ## License
804 |
805 | BSD licensed. See the LICENSE file for details.
806 |
--------------------------------------------------------------------------------
/23mymodules/vendor/github.com/gorilla/mux/doc.go:
--------------------------------------------------------------------------------
1 | // Copyright 2012 The Gorilla Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | /*
6 | Package mux implements a request router and dispatcher.
7 |
8 | The name mux stands for "HTTP request multiplexer". Like the standard
9 | http.ServeMux, mux.Router matches incoming requests against a list of
10 | registered routes and calls a handler for the route that matches the URL
11 | or other conditions. The main features are:
12 |
13 | * Requests can be matched based on URL host, path, path prefix, schemes,
14 | header and query values, HTTP methods or using custom matchers.
15 | * URL hosts, paths and query values can have variables with an optional
16 | regular expression.
17 | * Registered URLs can be built, or "reversed", which helps maintaining
18 | references to resources.
19 | * Routes can be used as subrouters: nested routes are only tested if the
20 | parent route matches. This is useful to define groups of routes that
21 | share common conditions like a host, a path prefix or other repeated
22 | attributes. As a bonus, this optimizes request matching.
23 | * It implements the http.Handler interface so it is compatible with the
24 | standard http.ServeMux.
25 |
26 | Let's start registering a couple of URL paths and handlers:
27 |
28 | func main() {
29 | r := mux.NewRouter()
30 | r.HandleFunc("/", HomeHandler)
31 | r.HandleFunc("/products", ProductsHandler)
32 | r.HandleFunc("/articles", ArticlesHandler)
33 | http.Handle("/", r)
34 | }
35 |
36 | Here we register three routes mapping URL paths to handlers. This is
37 | equivalent to how http.HandleFunc() works: if an incoming request URL matches
38 | one of the paths, the corresponding handler is called passing
39 | (http.ResponseWriter, *http.Request) as parameters.
40 |
41 | Paths can have variables. They are defined using the format {name} or
42 | {name:pattern}. If a regular expression pattern is not defined, the matched
43 | variable will be anything until the next slash. For example:
44 |
45 | r := mux.NewRouter()
46 | r.HandleFunc("/products/{key}", ProductHandler)
47 | r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
48 | r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
49 |
50 | Groups can be used inside patterns, as long as they are non-capturing (?:re). For example:
51 |
52 | r.HandleFunc("/articles/{category}/{sort:(?:asc|desc|new)}", ArticlesCategoryHandler)
53 |
54 | The names are used to create a map of route variables which can be retrieved
55 | calling mux.Vars():
56 |
57 | vars := mux.Vars(request)
58 | category := vars["category"]
59 |
60 | Note that if any capturing groups are present, mux will panic() during parsing. To prevent
61 | this, convert any capturing groups to non-capturing, e.g. change "/{sort:(asc|desc)}" to
62 | "/{sort:(?:asc|desc)}". This is a change from prior versions which behaved unpredictably
63 | when capturing groups were present.
64 |
65 | And this is all you need to know about the basic usage. More advanced options
66 | are explained below.
67 |
68 | Routes can also be restricted to a domain or subdomain. Just define a host
69 | pattern to be matched. They can also have variables:
70 |
71 | r := mux.NewRouter()
72 | // Only matches if domain is "www.example.com".
73 | r.Host("www.example.com")
74 | // Matches a dynamic subdomain.
75 | r.Host("{subdomain:[a-z]+}.domain.com")
76 |
77 | There are several other matchers that can be added. To match path prefixes:
78 |
79 | r.PathPrefix("/products/")
80 |
81 | ...or HTTP methods:
82 |
83 | r.Methods("GET", "POST")
84 |
85 | ...or URL schemes:
86 |
87 | r.Schemes("https")
88 |
89 | ...or header values:
90 |
91 | r.Headers("X-Requested-With", "XMLHttpRequest")
92 |
93 | ...or query values:
94 |
95 | r.Queries("key", "value")
96 |
97 | ...or to use a custom matcher function:
98 |
99 | r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
100 | return r.ProtoMajor == 0
101 | })
102 |
103 | ...and finally, it is possible to combine several matchers in a single route:
104 |
105 | r.HandleFunc("/products", ProductsHandler).
106 | Host("www.example.com").
107 | Methods("GET").
108 | Schemes("http")
109 |
110 | Setting the same matching conditions again and again can be boring, so we have
111 | a way to group several routes that share the same requirements.
112 | We call it "subrouting".
113 |
114 | For example, let's say we have several URLs that should only match when the
115 | host is "www.example.com". Create a route for that host and get a "subrouter"
116 | from it:
117 |
118 | r := mux.NewRouter()
119 | s := r.Host("www.example.com").Subrouter()
120 |
121 | Then register routes in the subrouter:
122 |
123 | s.HandleFunc("/products/", ProductsHandler)
124 | s.HandleFunc("/products/{key}", ProductHandler)
125 | s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
126 |
127 | The three URL paths we registered above will only be tested if the domain is
128 | "www.example.com", because the subrouter is tested first. This is not
129 | only convenient, but also optimizes request matching. You can create
130 | subrouters combining any attribute matchers accepted by a route.
131 |
132 | Subrouters can be used to create domain or path "namespaces": you define
133 | subrouters in a central place and then parts of the app can register its
134 | paths relatively to a given subrouter.
135 |
136 | There's one more thing about subroutes. When a subrouter has a path prefix,
137 | the inner routes use it as base for their paths:
138 |
139 | r := mux.NewRouter()
140 | s := r.PathPrefix("/products").Subrouter()
141 | // "/products/"
142 | s.HandleFunc("/", ProductsHandler)
143 | // "/products/{key}/"
144 | s.HandleFunc("/{key}/", ProductHandler)
145 | // "/products/{key}/details"
146 | s.HandleFunc("/{key}/details", ProductDetailsHandler)
147 |
148 | Note that the path provided to PathPrefix() represents a "wildcard": calling
149 | PathPrefix("/static/").Handler(...) means that the handler will be passed any
150 | request that matches "/static/*". This makes it easy to serve static files with mux:
151 |
152 | func main() {
153 | var dir string
154 |
155 | flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
156 | flag.Parse()
157 | r := mux.NewRouter()
158 |
159 | // This will serve files under http://localhost:8000/static/
160 | r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
161 |
162 | srv := &http.Server{
163 | Handler: r,
164 | Addr: "127.0.0.1:8000",
165 | // Good practice: enforce timeouts for servers you create!
166 | WriteTimeout: 15 * time.Second,
167 | ReadTimeout: 15 * time.Second,
168 | }
169 |
170 | log.Fatal(srv.ListenAndServe())
171 | }
172 |
173 | Now let's see how to build registered URLs.
174 |
175 | Routes can be named. All routes that define a name can have their URLs built,
176 | or "reversed". We define a name calling Name() on a route. For example:
177 |
178 | r := mux.NewRouter()
179 | r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
180 | Name("article")
181 |
182 | To build a URL, get the route and call the URL() method, passing a sequence of
183 | key/value pairs for the route variables. For the previous route, we would do:
184 |
185 | url, err := r.Get("article").URL("category", "technology", "id", "42")
186 |
187 | ...and the result will be a url.URL with the following path:
188 |
189 | "/articles/technology/42"
190 |
191 | This also works for host and query value variables:
192 |
193 | r := mux.NewRouter()
194 | r.Host("{subdomain}.domain.com").
195 | Path("/articles/{category}/{id:[0-9]+}").
196 | Queries("filter", "{filter}").
197 | HandlerFunc(ArticleHandler).
198 | Name("article")
199 |
200 | // url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla"
201 | url, err := r.Get("article").URL("subdomain", "news",
202 | "category", "technology",
203 | "id", "42",
204 | "filter", "gorilla")
205 |
206 | All variables defined in the route are required, and their values must
207 | conform to the corresponding patterns. These requirements guarantee that a
208 | generated URL will always match a registered route -- the only exception is
209 | for explicitly defined "build-only" routes which never match.
210 |
211 | Regex support also exists for matching Headers within a route. For example, we could do:
212 |
213 | r.HeadersRegexp("Content-Type", "application/(text|json)")
214 |
215 | ...and the route will match both requests with a Content-Type of `application/json` as well as
216 | `application/text`
217 |
218 | There's also a way to build only the URL host or path for a route:
219 | use the methods URLHost() or URLPath() instead. For the previous route,
220 | we would do:
221 |
222 | // "http://news.domain.com/"
223 | host, err := r.Get("article").URLHost("subdomain", "news")
224 |
225 | // "/articles/technology/42"
226 | path, err := r.Get("article").URLPath("category", "technology", "id", "42")
227 |
228 | And if you use subrouters, host and path defined separately can be built
229 | as well:
230 |
231 | r := mux.NewRouter()
232 | s := r.Host("{subdomain}.domain.com").Subrouter()
233 | s.Path("/articles/{category}/{id:[0-9]+}").
234 | HandlerFunc(ArticleHandler).
235 | Name("article")
236 |
237 | // "http://news.domain.com/articles/technology/42"
238 | url, err := r.Get("article").URL("subdomain", "news",
239 | "category", "technology",
240 | "id", "42")
241 |
242 | Mux supports the addition of middlewares to a Router, which are executed in the order they are added if a match is found, including its subrouters. Middlewares are (typically) small pieces of code which take one request, do something with it, and pass it down to another middleware or the final handler. Some common use cases for middleware are request logging, header manipulation, or ResponseWriter hijacking.
243 |
244 | type MiddlewareFunc func(http.Handler) http.Handler
245 |
246 | Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc (closures can access variables from the context where they are created).
247 |
248 | A very basic middleware which logs the URI of the request being handled could be written as:
249 |
250 | func simpleMw(next http.Handler) http.Handler {
251 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
252 | // Do stuff here
253 | log.Println(r.RequestURI)
254 | // Call the next handler, which can be another middleware in the chain, or the final handler.
255 | next.ServeHTTP(w, r)
256 | })
257 | }
258 |
259 | Middlewares can be added to a router using `Router.Use()`:
260 |
261 | r := mux.NewRouter()
262 | r.HandleFunc("/", handler)
263 | r.Use(simpleMw)
264 |
265 | A more complex authentication middleware, which maps session token to users, could be written as:
266 |
267 | // Define our struct
268 | type authenticationMiddleware struct {
269 | tokenUsers map[string]string
270 | }
271 |
272 | // Initialize it somewhere
273 | func (amw *authenticationMiddleware) Populate() {
274 | amw.tokenUsers["00000000"] = "user0"
275 | amw.tokenUsers["aaaaaaaa"] = "userA"
276 | amw.tokenUsers["05f717e5"] = "randomUser"
277 | amw.tokenUsers["deadbeef"] = "user0"
278 | }
279 |
280 | // Middleware function, which will be called for each request
281 | func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
282 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
283 | token := r.Header.Get("X-Session-Token")
284 |
285 | if user, found := amw.tokenUsers[token]; found {
286 | // We found the token in our map
287 | log.Printf("Authenticated user %s\n", user)
288 | next.ServeHTTP(w, r)
289 | } else {
290 | http.Error(w, "Forbidden", http.StatusForbidden)
291 | }
292 | })
293 | }
294 |
295 | r := mux.NewRouter()
296 | r.HandleFunc("/", handler)
297 |
298 | amw := authenticationMiddleware{tokenUsers: make(map[string]string)}
299 | amw.Populate()
300 |
301 | r.Use(amw.Middleware)
302 |
303 | Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to.
304 |
305 | */
306 | package mux
307 |
--------------------------------------------------------------------------------
/23mymodules/vendor/github.com/gorilla/mux/middleware.go:
--------------------------------------------------------------------------------
1 | package mux
2 |
3 | import (
4 | "net/http"
5 | "strings"
6 | )
7 |
8 | // MiddlewareFunc is a function which receives an http.Handler and returns another http.Handler.
9 | // Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed
10 | // to it, and then calls the handler passed as parameter to the MiddlewareFunc.
11 | type MiddlewareFunc func(http.Handler) http.Handler
12 |
13 | // middleware interface is anything which implements a MiddlewareFunc named Middleware.
14 | type middleware interface {
15 | Middleware(handler http.Handler) http.Handler
16 | }
17 |
18 | // Middleware allows MiddlewareFunc to implement the middleware interface.
19 | func (mw MiddlewareFunc) Middleware(handler http.Handler) http.Handler {
20 | return mw(handler)
21 | }
22 |
23 | // Use appends a MiddlewareFunc to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router.
24 | func (r *Router) Use(mwf ...MiddlewareFunc) {
25 | for _, fn := range mwf {
26 | r.middlewares = append(r.middlewares, fn)
27 | }
28 | }
29 |
30 | // useInterface appends a middleware to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router.
31 | func (r *Router) useInterface(mw middleware) {
32 | r.middlewares = append(r.middlewares, mw)
33 | }
34 |
35 | // CORSMethodMiddleware automatically sets the Access-Control-Allow-Methods response header
36 | // on requests for routes that have an OPTIONS method matcher to all the method matchers on
37 | // the route. Routes that do not explicitly handle OPTIONS requests will not be processed
38 | // by the middleware. See examples for usage.
39 | func CORSMethodMiddleware(r *Router) MiddlewareFunc {
40 | return func(next http.Handler) http.Handler {
41 | return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
42 | allMethods, err := getAllMethodsForRoute(r, req)
43 | if err == nil {
44 | for _, v := range allMethods {
45 | if v == http.MethodOptions {
46 | w.Header().Set("Access-Control-Allow-Methods", strings.Join(allMethods, ","))
47 | }
48 | }
49 | }
50 |
51 | next.ServeHTTP(w, req)
52 | })
53 | }
54 | }
55 |
56 | // getAllMethodsForRoute returns all the methods from method matchers matching a given
57 | // request.
58 | func getAllMethodsForRoute(r *Router, req *http.Request) ([]string, error) {
59 | var allMethods []string
60 |
61 | for _, route := range r.routes {
62 | var match RouteMatch
63 | if route.Match(req, &match) || match.MatchErr == ErrMethodMismatch {
64 | methods, err := route.GetMethods()
65 | if err != nil {
66 | return nil, err
67 | }
68 |
69 | allMethods = append(allMethods, methods...)
70 | }
71 | }
72 |
73 | return allMethods, nil
74 | }
75 |
--------------------------------------------------------------------------------
/23mymodules/vendor/github.com/gorilla/mux/mux.go:
--------------------------------------------------------------------------------
1 | // Copyright 2012 The Gorilla Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package mux
6 |
7 | import (
8 | "context"
9 | "errors"
10 | "fmt"
11 | "net/http"
12 | "path"
13 | "regexp"
14 | )
15 |
16 | var (
17 | // ErrMethodMismatch is returned when the method in the request does not match
18 | // the method defined against the route.
19 | ErrMethodMismatch = errors.New("method is not allowed")
20 | // ErrNotFound is returned when no route match is found.
21 | ErrNotFound = errors.New("no matching route was found")
22 | )
23 |
24 | // NewRouter returns a new router instance.
25 | func NewRouter() *Router {
26 | return &Router{namedRoutes: make(map[string]*Route)}
27 | }
28 |
29 | // Router registers routes to be matched and dispatches a handler.
30 | //
31 | // It implements the http.Handler interface, so it can be registered to serve
32 | // requests:
33 | //
34 | // var router = mux.NewRouter()
35 | //
36 | // func main() {
37 | // http.Handle("/", router)
38 | // }
39 | //
40 | // Or, for Google App Engine, register it in a init() function:
41 | //
42 | // func init() {
43 | // http.Handle("/", router)
44 | // }
45 | //
46 | // This will send all incoming requests to the router.
47 | type Router struct {
48 | // Configurable Handler to be used when no route matches.
49 | NotFoundHandler http.Handler
50 |
51 | // Configurable Handler to be used when the request method does not match the route.
52 | MethodNotAllowedHandler http.Handler
53 |
54 | // Routes to be matched, in order.
55 | routes []*Route
56 |
57 | // Routes by name for URL building.
58 | namedRoutes map[string]*Route
59 |
60 | // If true, do not clear the request context after handling the request.
61 | //
62 | // Deprecated: No effect, since the context is stored on the request itself.
63 | KeepContext bool
64 |
65 | // Slice of middlewares to be called after a match is found
66 | middlewares []middleware
67 |
68 | // configuration shared with `Route`
69 | routeConf
70 | }
71 |
72 | // common route configuration shared between `Router` and `Route`
73 | type routeConf struct {
74 | // If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to"
75 | useEncodedPath bool
76 |
77 | // If true, when the path pattern is "/path/", accessing "/path" will
78 | // redirect to the former and vice versa.
79 | strictSlash bool
80 |
81 | // If true, when the path pattern is "/path//to", accessing "/path//to"
82 | // will not redirect
83 | skipClean bool
84 |
85 | // Manager for the variables from host and path.
86 | regexp routeRegexpGroup
87 |
88 | // List of matchers.
89 | matchers []matcher
90 |
91 | // The scheme used when building URLs.
92 | buildScheme string
93 |
94 | buildVarsFunc BuildVarsFunc
95 | }
96 |
97 | // returns an effective deep copy of `routeConf`
98 | func copyRouteConf(r routeConf) routeConf {
99 | c := r
100 |
101 | if r.regexp.path != nil {
102 | c.regexp.path = copyRouteRegexp(r.regexp.path)
103 | }
104 |
105 | if r.regexp.host != nil {
106 | c.regexp.host = copyRouteRegexp(r.regexp.host)
107 | }
108 |
109 | c.regexp.queries = make([]*routeRegexp, 0, len(r.regexp.queries))
110 | for _, q := range r.regexp.queries {
111 | c.regexp.queries = append(c.regexp.queries, copyRouteRegexp(q))
112 | }
113 |
114 | c.matchers = make([]matcher, len(r.matchers))
115 | copy(c.matchers, r.matchers)
116 |
117 | return c
118 | }
119 |
120 | func copyRouteRegexp(r *routeRegexp) *routeRegexp {
121 | c := *r
122 | return &c
123 | }
124 |
125 | // Match attempts to match the given request against the router's registered routes.
126 | //
127 | // If the request matches a route of this router or one of its subrouters the Route,
128 | // Handler, and Vars fields of the the match argument are filled and this function
129 | // returns true.
130 | //
131 | // If the request does not match any of this router's or its subrouters' routes
132 | // then this function returns false. If available, a reason for the match failure
133 | // will be filled in the match argument's MatchErr field. If the match failure type
134 | // (eg: not found) has a registered handler, the handler is assigned to the Handler
135 | // field of the match argument.
136 | func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
137 | for _, route := range r.routes {
138 | if route.Match(req, match) {
139 | // Build middleware chain if no error was found
140 | if match.MatchErr == nil {
141 | for i := len(r.middlewares) - 1; i >= 0; i-- {
142 | match.Handler = r.middlewares[i].Middleware(match.Handler)
143 | }
144 | }
145 | return true
146 | }
147 | }
148 |
149 | if match.MatchErr == ErrMethodMismatch {
150 | if r.MethodNotAllowedHandler != nil {
151 | match.Handler = r.MethodNotAllowedHandler
152 | return true
153 | }
154 |
155 | return false
156 | }
157 |
158 | // Closest match for a router (includes sub-routers)
159 | if r.NotFoundHandler != nil {
160 | match.Handler = r.NotFoundHandler
161 | match.MatchErr = ErrNotFound
162 | return true
163 | }
164 |
165 | match.MatchErr = ErrNotFound
166 | return false
167 | }
168 |
169 | // ServeHTTP dispatches the handler registered in the matched route.
170 | //
171 | // When there is a match, the route variables can be retrieved calling
172 | // mux.Vars(request).
173 | func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
174 | if !r.skipClean {
175 | path := req.URL.Path
176 | if r.useEncodedPath {
177 | path = req.URL.EscapedPath()
178 | }
179 | // Clean path to canonical form and redirect.
180 | if p := cleanPath(path); p != path {
181 |
182 | // Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query.
183 | // This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue:
184 | // http://code.google.com/p/go/issues/detail?id=5252
185 | url := *req.URL
186 | url.Path = p
187 | p = url.String()
188 |
189 | w.Header().Set("Location", p)
190 | w.WriteHeader(http.StatusMovedPermanently)
191 | return
192 | }
193 | }
194 | var match RouteMatch
195 | var handler http.Handler
196 | if r.Match(req, &match) {
197 | handler = match.Handler
198 | req = requestWithVars(req, match.Vars)
199 | req = requestWithRoute(req, match.Route)
200 | }
201 |
202 | if handler == nil && match.MatchErr == ErrMethodMismatch {
203 | handler = methodNotAllowedHandler()
204 | }
205 |
206 | if handler == nil {
207 | handler = http.NotFoundHandler()
208 | }
209 |
210 | handler.ServeHTTP(w, req)
211 | }
212 |
213 | // Get returns a route registered with the given name.
214 | func (r *Router) Get(name string) *Route {
215 | return r.namedRoutes[name]
216 | }
217 |
218 | // GetRoute returns a route registered with the given name. This method
219 | // was renamed to Get() and remains here for backwards compatibility.
220 | func (r *Router) GetRoute(name string) *Route {
221 | return r.namedRoutes[name]
222 | }
223 |
224 | // StrictSlash defines the trailing slash behavior for new routes. The initial
225 | // value is false.
226 | //
227 | // When true, if the route path is "/path/", accessing "/path" will perform a redirect
228 | // to the former and vice versa. In other words, your application will always
229 | // see the path as specified in the route.
230 | //
231 | // When false, if the route path is "/path", accessing "/path/" will not match
232 | // this route and vice versa.
233 | //
234 | // The re-direct is a HTTP 301 (Moved Permanently). Note that when this is set for
235 | // routes with a non-idempotent method (e.g. POST, PUT), the subsequent re-directed
236 | // request will be made as a GET by most clients. Use middleware or client settings
237 | // to modify this behaviour as needed.
238 | //
239 | // Special case: when a route sets a path prefix using the PathPrefix() method,
240 | // strict slash is ignored for that route because the redirect behavior can't
241 | // be determined from a prefix alone. However, any subrouters created from that
242 | // route inherit the original StrictSlash setting.
243 | func (r *Router) StrictSlash(value bool) *Router {
244 | r.strictSlash = value
245 | return r
246 | }
247 |
248 | // SkipClean defines the path cleaning behaviour for new routes. The initial
249 | // value is false. Users should be careful about which routes are not cleaned
250 | //
251 | // When true, if the route path is "/path//to", it will remain with the double
252 | // slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/
253 | //
254 | // When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will
255 | // become /fetch/http/xkcd.com/534
256 | func (r *Router) SkipClean(value bool) *Router {
257 | r.skipClean = value
258 | return r
259 | }
260 |
261 | // UseEncodedPath tells the router to match the encoded original path
262 | // to the routes.
263 | // For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to".
264 | //
265 | // If not called, the router will match the unencoded path to the routes.
266 | // For eg. "/path/foo%2Fbar/to" will match the path "/path/foo/bar/to"
267 | func (r *Router) UseEncodedPath() *Router {
268 | r.useEncodedPath = true
269 | return r
270 | }
271 |
272 | // ----------------------------------------------------------------------------
273 | // Route factories
274 | // ----------------------------------------------------------------------------
275 |
276 | // NewRoute registers an empty route.
277 | func (r *Router) NewRoute() *Route {
278 | // initialize a route with a copy of the parent router's configuration
279 | route := &Route{routeConf: copyRouteConf(r.routeConf), namedRoutes: r.namedRoutes}
280 | r.routes = append(r.routes, route)
281 | return route
282 | }
283 |
284 | // Name registers a new route with a name.
285 | // See Route.Name().
286 | func (r *Router) Name(name string) *Route {
287 | return r.NewRoute().Name(name)
288 | }
289 |
290 | // Handle registers a new route with a matcher for the URL path.
291 | // See Route.Path() and Route.Handler().
292 | func (r *Router) Handle(path string, handler http.Handler) *Route {
293 | return r.NewRoute().Path(path).Handler(handler)
294 | }
295 |
296 | // HandleFunc registers a new route with a matcher for the URL path.
297 | // See Route.Path() and Route.HandlerFunc().
298 | func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,
299 | *http.Request)) *Route {
300 | return r.NewRoute().Path(path).HandlerFunc(f)
301 | }
302 |
303 | // Headers registers a new route with a matcher for request header values.
304 | // See Route.Headers().
305 | func (r *Router) Headers(pairs ...string) *Route {
306 | return r.NewRoute().Headers(pairs...)
307 | }
308 |
309 | // Host registers a new route with a matcher for the URL host.
310 | // See Route.Host().
311 | func (r *Router) Host(tpl string) *Route {
312 | return r.NewRoute().Host(tpl)
313 | }
314 |
315 | // MatcherFunc registers a new route with a custom matcher function.
316 | // See Route.MatcherFunc().
317 | func (r *Router) MatcherFunc(f MatcherFunc) *Route {
318 | return r.NewRoute().MatcherFunc(f)
319 | }
320 |
321 | // Methods registers a new route with a matcher for HTTP methods.
322 | // See Route.Methods().
323 | func (r *Router) Methods(methods ...string) *Route {
324 | return r.NewRoute().Methods(methods...)
325 | }
326 |
327 | // Path registers a new route with a matcher for the URL path.
328 | // See Route.Path().
329 | func (r *Router) Path(tpl string) *Route {
330 | return r.NewRoute().Path(tpl)
331 | }
332 |
333 | // PathPrefix registers a new route with a matcher for the URL path prefix.
334 | // See Route.PathPrefix().
335 | func (r *Router) PathPrefix(tpl string) *Route {
336 | return r.NewRoute().PathPrefix(tpl)
337 | }
338 |
339 | // Queries registers a new route with a matcher for URL query values.
340 | // See Route.Queries().
341 | func (r *Router) Queries(pairs ...string) *Route {
342 | return r.NewRoute().Queries(pairs...)
343 | }
344 |
345 | // Schemes registers a new route with a matcher for URL schemes.
346 | // See Route.Schemes().
347 | func (r *Router) Schemes(schemes ...string) *Route {
348 | return r.NewRoute().Schemes(schemes...)
349 | }
350 |
351 | // BuildVarsFunc registers a new route with a custom function for modifying
352 | // route variables before building a URL.
353 | func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {
354 | return r.NewRoute().BuildVarsFunc(f)
355 | }
356 |
357 | // Walk walks the router and all its sub-routers, calling walkFn for each route
358 | // in the tree. The routes are walked in the order they were added. Sub-routers
359 | // are explored depth-first.
360 | func (r *Router) Walk(walkFn WalkFunc) error {
361 | return r.walk(walkFn, []*Route{})
362 | }
363 |
364 | // SkipRouter is used as a return value from WalkFuncs to indicate that the
365 | // router that walk is about to descend down to should be skipped.
366 | var SkipRouter = errors.New("skip this router")
367 |
368 | // WalkFunc is the type of the function called for each route visited by Walk.
369 | // At every invocation, it is given the current route, and the current router,
370 | // and a list of ancestor routes that lead to the current route.
371 | type WalkFunc func(route *Route, router *Router, ancestors []*Route) error
372 |
373 | func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
374 | for _, t := range r.routes {
375 | err := walkFn(t, r, ancestors)
376 | if err == SkipRouter {
377 | continue
378 | }
379 | if err != nil {
380 | return err
381 | }
382 | for _, sr := range t.matchers {
383 | if h, ok := sr.(*Router); ok {
384 | ancestors = append(ancestors, t)
385 | err := h.walk(walkFn, ancestors)
386 | if err != nil {
387 | return err
388 | }
389 | ancestors = ancestors[:len(ancestors)-1]
390 | }
391 | }
392 | if h, ok := t.handler.(*Router); ok {
393 | ancestors = append(ancestors, t)
394 | err := h.walk(walkFn, ancestors)
395 | if err != nil {
396 | return err
397 | }
398 | ancestors = ancestors[:len(ancestors)-1]
399 | }
400 | }
401 | return nil
402 | }
403 |
404 | // ----------------------------------------------------------------------------
405 | // Context
406 | // ----------------------------------------------------------------------------
407 |
408 | // RouteMatch stores information about a matched route.
409 | type RouteMatch struct {
410 | Route *Route
411 | Handler http.Handler
412 | Vars map[string]string
413 |
414 | // MatchErr is set to appropriate matching error
415 | // It is set to ErrMethodMismatch if there is a mismatch in
416 | // the request method and route method
417 | MatchErr error
418 | }
419 |
420 | type contextKey int
421 |
422 | const (
423 | varsKey contextKey = iota
424 | routeKey
425 | )
426 |
427 | // Vars returns the route variables for the current request, if any.
428 | func Vars(r *http.Request) map[string]string {
429 | if rv := r.Context().Value(varsKey); rv != nil {
430 | return rv.(map[string]string)
431 | }
432 | return nil
433 | }
434 |
435 | // CurrentRoute returns the matched route for the current request, if any.
436 | // This only works when called inside the handler of the matched route
437 | // because the matched route is stored in the request context which is cleared
438 | // after the handler returns.
439 | func CurrentRoute(r *http.Request) *Route {
440 | if rv := r.Context().Value(routeKey); rv != nil {
441 | return rv.(*Route)
442 | }
443 | return nil
444 | }
445 |
446 | func requestWithVars(r *http.Request, vars map[string]string) *http.Request {
447 | ctx := context.WithValue(r.Context(), varsKey, vars)
448 | return r.WithContext(ctx)
449 | }
450 |
451 | func requestWithRoute(r *http.Request, route *Route) *http.Request {
452 | ctx := context.WithValue(r.Context(), routeKey, route)
453 | return r.WithContext(ctx)
454 | }
455 |
456 | // ----------------------------------------------------------------------------
457 | // Helpers
458 | // ----------------------------------------------------------------------------
459 |
460 | // cleanPath returns the canonical path for p, eliminating . and .. elements.
461 | // Borrowed from the net/http package.
462 | func cleanPath(p string) string {
463 | if p == "" {
464 | return "/"
465 | }
466 | if p[0] != '/' {
467 | p = "/" + p
468 | }
469 | np := path.Clean(p)
470 | // path.Clean removes trailing slash except for root;
471 | // put the trailing slash back if necessary.
472 | if p[len(p)-1] == '/' && np != "/" {
473 | np += "/"
474 | }
475 |
476 | return np
477 | }
478 |
479 | // uniqueVars returns an error if two slices contain duplicated strings.
480 | func uniqueVars(s1, s2 []string) error {
481 | for _, v1 := range s1 {
482 | for _, v2 := range s2 {
483 | if v1 == v2 {
484 | return fmt.Errorf("mux: duplicated route variable %q", v2)
485 | }
486 | }
487 | }
488 | return nil
489 | }
490 |
491 | // checkPairs returns the count of strings passed in, and an error if
492 | // the count is not an even number.
493 | func checkPairs(pairs ...string) (int, error) {
494 | length := len(pairs)
495 | if length%2 != 0 {
496 | return length, fmt.Errorf(
497 | "mux: number of parameters must be multiple of 2, got %v", pairs)
498 | }
499 | return length, nil
500 | }
501 |
502 | // mapFromPairsToString converts variadic string parameters to a
503 | // string to string map.
504 | func mapFromPairsToString(pairs ...string) (map[string]string, error) {
505 | length, err := checkPairs(pairs...)
506 | if err != nil {
507 | return nil, err
508 | }
509 | m := make(map[string]string, length/2)
510 | for i := 0; i < length; i += 2 {
511 | m[pairs[i]] = pairs[i+1]
512 | }
513 | return m, nil
514 | }
515 |
516 | // mapFromPairsToRegex converts variadic string parameters to a
517 | // string to regex map.
518 | func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
519 | length, err := checkPairs(pairs...)
520 | if err != nil {
521 | return nil, err
522 | }
523 | m := make(map[string]*regexp.Regexp, length/2)
524 | for i := 0; i < length; i += 2 {
525 | regex, err := regexp.Compile(pairs[i+1])
526 | if err != nil {
527 | return nil, err
528 | }
529 | m[pairs[i]] = regex
530 | }
531 | return m, nil
532 | }
533 |
534 | // matchInArray returns true if the given string value is in the array.
535 | func matchInArray(arr []string, value string) bool {
536 | for _, v := range arr {
537 | if v == value {
538 | return true
539 | }
540 | }
541 | return false
542 | }
543 |
544 | // matchMapWithString returns true if the given key/value pairs exist in a given map.
545 | func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool {
546 | for k, v := range toCheck {
547 | // Check if key exists.
548 | if canonicalKey {
549 | k = http.CanonicalHeaderKey(k)
550 | }
551 | if values := toMatch[k]; values == nil {
552 | return false
553 | } else if v != "" {
554 | // If value was defined as an empty string we only check that the
555 | // key exists. Otherwise we also check for equality.
556 | valueExists := false
557 | for _, value := range values {
558 | if v == value {
559 | valueExists = true
560 | break
561 | }
562 | }
563 | if !valueExists {
564 | return false
565 | }
566 | }
567 | }
568 | return true
569 | }
570 |
571 | // matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against
572 | // the given regex
573 | func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool {
574 | for k, v := range toCheck {
575 | // Check if key exists.
576 | if canonicalKey {
577 | k = http.CanonicalHeaderKey(k)
578 | }
579 | if values := toMatch[k]; values == nil {
580 | return false
581 | } else if v != nil {
582 | // If value was defined as an empty string we only check that the
583 | // key exists. Otherwise we also check for equality.
584 | valueExists := false
585 | for _, value := range values {
586 | if v.MatchString(value) {
587 | valueExists = true
588 | break
589 | }
590 | }
591 | if !valueExists {
592 | return false
593 | }
594 | }
595 | }
596 | return true
597 | }
598 |
599 | // methodNotAllowed replies to the request with an HTTP status code 405.
600 | func methodNotAllowed(w http.ResponseWriter, r *http.Request) {
601 | w.WriteHeader(http.StatusMethodNotAllowed)
602 | }
603 |
604 | // methodNotAllowedHandler returns a simple request handler
605 | // that replies to each request with a status code 405.
606 | func methodNotAllowedHandler() http.Handler { return http.HandlerFunc(methodNotAllowed) }
607 |
--------------------------------------------------------------------------------
/23mymodules/vendor/github.com/gorilla/mux/regexp.go:
--------------------------------------------------------------------------------
1 | // Copyright 2012 The Gorilla Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package mux
6 |
7 | import (
8 | "bytes"
9 | "fmt"
10 | "net/http"
11 | "net/url"
12 | "regexp"
13 | "strconv"
14 | "strings"
15 | )
16 |
17 | type routeRegexpOptions struct {
18 | strictSlash bool
19 | useEncodedPath bool
20 | }
21 |
22 | type regexpType int
23 |
24 | const (
25 | regexpTypePath regexpType = 0
26 | regexpTypeHost regexpType = 1
27 | regexpTypePrefix regexpType = 2
28 | regexpTypeQuery regexpType = 3
29 | )
30 |
31 | // newRouteRegexp parses a route template and returns a routeRegexp,
32 | // used to match a host, a path or a query string.
33 | //
34 | // It will extract named variables, assemble a regexp to be matched, create
35 | // a "reverse" template to build URLs and compile regexps to validate variable
36 | // values used in URL building.
37 | //
38 | // Previously we accepted only Python-like identifiers for variable
39 | // names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that
40 | // name and pattern can't be empty, and names can't contain a colon.
41 | func newRouteRegexp(tpl string, typ regexpType, options routeRegexpOptions) (*routeRegexp, error) {
42 | // Check if it is well-formed.
43 | idxs, errBraces := braceIndices(tpl)
44 | if errBraces != nil {
45 | return nil, errBraces
46 | }
47 | // Backup the original.
48 | template := tpl
49 | // Now let's parse it.
50 | defaultPattern := "[^/]+"
51 | if typ == regexpTypeQuery {
52 | defaultPattern = ".*"
53 | } else if typ == regexpTypeHost {
54 | defaultPattern = "[^.]+"
55 | }
56 | // Only match strict slash if not matching
57 | if typ != regexpTypePath {
58 | options.strictSlash = false
59 | }
60 | // Set a flag for strictSlash.
61 | endSlash := false
62 | if options.strictSlash && strings.HasSuffix(tpl, "/") {
63 | tpl = tpl[:len(tpl)-1]
64 | endSlash = true
65 | }
66 | varsN := make([]string, len(idxs)/2)
67 | varsR := make([]*regexp.Regexp, len(idxs)/2)
68 | pattern := bytes.NewBufferString("")
69 | pattern.WriteByte('^')
70 | reverse := bytes.NewBufferString("")
71 | var end int
72 | var err error
73 | for i := 0; i < len(idxs); i += 2 {
74 | // Set all values we are interested in.
75 | raw := tpl[end:idxs[i]]
76 | end = idxs[i+1]
77 | parts := strings.SplitN(tpl[idxs[i]+1:end-1], ":", 2)
78 | name := parts[0]
79 | patt := defaultPattern
80 | if len(parts) == 2 {
81 | patt = parts[1]
82 | }
83 | // Name or pattern can't be empty.
84 | if name == "" || patt == "" {
85 | return nil, fmt.Errorf("mux: missing name or pattern in %q",
86 | tpl[idxs[i]:end])
87 | }
88 | // Build the regexp pattern.
89 | fmt.Fprintf(pattern, "%s(?P<%s>%s)", regexp.QuoteMeta(raw), varGroupName(i/2), patt)
90 |
91 | // Build the reverse template.
92 | fmt.Fprintf(reverse, "%s%%s", raw)
93 |
94 | // Append variable name and compiled pattern.
95 | varsN[i/2] = name
96 | varsR[i/2], err = regexp.Compile(fmt.Sprintf("^%s$", patt))
97 | if err != nil {
98 | return nil, err
99 | }
100 | }
101 | // Add the remaining.
102 | raw := tpl[end:]
103 | pattern.WriteString(regexp.QuoteMeta(raw))
104 | if options.strictSlash {
105 | pattern.WriteString("[/]?")
106 | }
107 | if typ == regexpTypeQuery {
108 | // Add the default pattern if the query value is empty
109 | if queryVal := strings.SplitN(template, "=", 2)[1]; queryVal == "" {
110 | pattern.WriteString(defaultPattern)
111 | }
112 | }
113 | if typ != regexpTypePrefix {
114 | pattern.WriteByte('$')
115 | }
116 |
117 | var wildcardHostPort bool
118 | if typ == regexpTypeHost {
119 | if !strings.Contains(pattern.String(), ":") {
120 | wildcardHostPort = true
121 | }
122 | }
123 | reverse.WriteString(raw)
124 | if endSlash {
125 | reverse.WriteByte('/')
126 | }
127 | // Compile full regexp.
128 | reg, errCompile := regexp.Compile(pattern.String())
129 | if errCompile != nil {
130 | return nil, errCompile
131 | }
132 |
133 | // Check for capturing groups which used to work in older versions
134 | if reg.NumSubexp() != len(idxs)/2 {
135 | panic(fmt.Sprintf("route %s contains capture groups in its regexp. ", template) +
136 | "Only non-capturing groups are accepted: e.g. (?:pattern) instead of (pattern)")
137 | }
138 |
139 | // Done!
140 | return &routeRegexp{
141 | template: template,
142 | regexpType: typ,
143 | options: options,
144 | regexp: reg,
145 | reverse: reverse.String(),
146 | varsN: varsN,
147 | varsR: varsR,
148 | wildcardHostPort: wildcardHostPort,
149 | }, nil
150 | }
151 |
152 | // routeRegexp stores a regexp to match a host or path and information to
153 | // collect and validate route variables.
154 | type routeRegexp struct {
155 | // The unmodified template.
156 | template string
157 | // The type of match
158 | regexpType regexpType
159 | // Options for matching
160 | options routeRegexpOptions
161 | // Expanded regexp.
162 | regexp *regexp.Regexp
163 | // Reverse template.
164 | reverse string
165 | // Variable names.
166 | varsN []string
167 | // Variable regexps (validators).
168 | varsR []*regexp.Regexp
169 | // Wildcard host-port (no strict port match in hostname)
170 | wildcardHostPort bool
171 | }
172 |
173 | // Match matches the regexp against the URL host or path.
174 | func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
175 | if r.regexpType == regexpTypeHost {
176 | host := getHost(req)
177 | if r.wildcardHostPort {
178 | // Don't be strict on the port match
179 | if i := strings.Index(host, ":"); i != -1 {
180 | host = host[:i]
181 | }
182 | }
183 | return r.regexp.MatchString(host)
184 | }
185 |
186 | if r.regexpType == regexpTypeQuery {
187 | return r.matchQueryString(req)
188 | }
189 | path := req.URL.Path
190 | if r.options.useEncodedPath {
191 | path = req.URL.EscapedPath()
192 | }
193 | return r.regexp.MatchString(path)
194 | }
195 |
196 | // url builds a URL part using the given values.
197 | func (r *routeRegexp) url(values map[string]string) (string, error) {
198 | urlValues := make([]interface{}, len(r.varsN), len(r.varsN))
199 | for k, v := range r.varsN {
200 | value, ok := values[v]
201 | if !ok {
202 | return "", fmt.Errorf("mux: missing route variable %q", v)
203 | }
204 | if r.regexpType == regexpTypeQuery {
205 | value = url.QueryEscape(value)
206 | }
207 | urlValues[k] = value
208 | }
209 | rv := fmt.Sprintf(r.reverse, urlValues...)
210 | if !r.regexp.MatchString(rv) {
211 | // The URL is checked against the full regexp, instead of checking
212 | // individual variables. This is faster but to provide a good error
213 | // message, we check individual regexps if the URL doesn't match.
214 | for k, v := range r.varsN {
215 | if !r.varsR[k].MatchString(values[v]) {
216 | return "", fmt.Errorf(
217 | "mux: variable %q doesn't match, expected %q", values[v],
218 | r.varsR[k].String())
219 | }
220 | }
221 | }
222 | return rv, nil
223 | }
224 |
225 | // getURLQuery returns a single query parameter from a request URL.
226 | // For a URL with foo=bar&baz=ding, we return only the relevant key
227 | // value pair for the routeRegexp.
228 | func (r *routeRegexp) getURLQuery(req *http.Request) string {
229 | if r.regexpType != regexpTypeQuery {
230 | return ""
231 | }
232 | templateKey := strings.SplitN(r.template, "=", 2)[0]
233 | val, ok := findFirstQueryKey(req.URL.RawQuery, templateKey)
234 | if ok {
235 | return templateKey + "=" + val
236 | }
237 | return ""
238 | }
239 |
240 | // findFirstQueryKey returns the same result as (*url.URL).Query()[key][0].
241 | // If key was not found, empty string and false is returned.
242 | func findFirstQueryKey(rawQuery, key string) (value string, ok bool) {
243 | query := []byte(rawQuery)
244 | for len(query) > 0 {
245 | foundKey := query
246 | if i := bytes.IndexAny(foundKey, "&;"); i >= 0 {
247 | foundKey, query = foundKey[:i], foundKey[i+1:]
248 | } else {
249 | query = query[:0]
250 | }
251 | if len(foundKey) == 0 {
252 | continue
253 | }
254 | var value []byte
255 | if i := bytes.IndexByte(foundKey, '='); i >= 0 {
256 | foundKey, value = foundKey[:i], foundKey[i+1:]
257 | }
258 | if len(foundKey) < len(key) {
259 | // Cannot possibly be key.
260 | continue
261 | }
262 | keyString, err := url.QueryUnescape(string(foundKey))
263 | if err != nil {
264 | continue
265 | }
266 | if keyString != key {
267 | continue
268 | }
269 | valueString, err := url.QueryUnescape(string(value))
270 | if err != nil {
271 | continue
272 | }
273 | return valueString, true
274 | }
275 | return "", false
276 | }
277 |
278 | func (r *routeRegexp) matchQueryString(req *http.Request) bool {
279 | return r.regexp.MatchString(r.getURLQuery(req))
280 | }
281 |
282 | // braceIndices returns the first level curly brace indices from a string.
283 | // It returns an error in case of unbalanced braces.
284 | func braceIndices(s string) ([]int, error) {
285 | var level, idx int
286 | var idxs []int
287 | for i := 0; i < len(s); i++ {
288 | switch s[i] {
289 | case '{':
290 | if level++; level == 1 {
291 | idx = i
292 | }
293 | case '}':
294 | if level--; level == 0 {
295 | idxs = append(idxs, idx, i+1)
296 | } else if level < 0 {
297 | return nil, fmt.Errorf("mux: unbalanced braces in %q", s)
298 | }
299 | }
300 | }
301 | if level != 0 {
302 | return nil, fmt.Errorf("mux: unbalanced braces in %q", s)
303 | }
304 | return idxs, nil
305 | }
306 |
307 | // varGroupName builds a capturing group name for the indexed variable.
308 | func varGroupName(idx int) string {
309 | return "v" + strconv.Itoa(idx)
310 | }
311 |
312 | // ----------------------------------------------------------------------------
313 | // routeRegexpGroup
314 | // ----------------------------------------------------------------------------
315 |
316 | // routeRegexpGroup groups the route matchers that carry variables.
317 | type routeRegexpGroup struct {
318 | host *routeRegexp
319 | path *routeRegexp
320 | queries []*routeRegexp
321 | }
322 |
323 | // setMatch extracts the variables from the URL once a route matches.
324 | func (v routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) {
325 | // Store host variables.
326 | if v.host != nil {
327 | host := getHost(req)
328 | if v.host.wildcardHostPort {
329 | // Don't be strict on the port match
330 | if i := strings.Index(host, ":"); i != -1 {
331 | host = host[:i]
332 | }
333 | }
334 | matches := v.host.regexp.FindStringSubmatchIndex(host)
335 | if len(matches) > 0 {
336 | extractVars(host, matches, v.host.varsN, m.Vars)
337 | }
338 | }
339 | path := req.URL.Path
340 | if r.useEncodedPath {
341 | path = req.URL.EscapedPath()
342 | }
343 | // Store path variables.
344 | if v.path != nil {
345 | matches := v.path.regexp.FindStringSubmatchIndex(path)
346 | if len(matches) > 0 {
347 | extractVars(path, matches, v.path.varsN, m.Vars)
348 | // Check if we should redirect.
349 | if v.path.options.strictSlash {
350 | p1 := strings.HasSuffix(path, "/")
351 | p2 := strings.HasSuffix(v.path.template, "/")
352 | if p1 != p2 {
353 | u, _ := url.Parse(req.URL.String())
354 | if p1 {
355 | u.Path = u.Path[:len(u.Path)-1]
356 | } else {
357 | u.Path += "/"
358 | }
359 | m.Handler = http.RedirectHandler(u.String(), http.StatusMovedPermanently)
360 | }
361 | }
362 | }
363 | }
364 | // Store query string variables.
365 | for _, q := range v.queries {
366 | queryURL := q.getURLQuery(req)
367 | matches := q.regexp.FindStringSubmatchIndex(queryURL)
368 | if len(matches) > 0 {
369 | extractVars(queryURL, matches, q.varsN, m.Vars)
370 | }
371 | }
372 | }
373 |
374 | // getHost tries its best to return the request host.
375 | // According to section 14.23 of RFC 2616 the Host header
376 | // can include the port number if the default value of 80 is not used.
377 | func getHost(r *http.Request) string {
378 | if r.URL.IsAbs() {
379 | return r.URL.Host
380 | }
381 | return r.Host
382 | }
383 |
384 | func extractVars(input string, matches []int, names []string, output map[string]string) {
385 | for i, name := range names {
386 | output[name] = input[matches[2*i+2]:matches[2*i+3]]
387 | }
388 | }
389 |
--------------------------------------------------------------------------------
/23mymodules/vendor/github.com/gorilla/mux/route.go:
--------------------------------------------------------------------------------
1 | // Copyright 2012 The Gorilla Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package mux
6 |
7 | import (
8 | "errors"
9 | "fmt"
10 | "net/http"
11 | "net/url"
12 | "regexp"
13 | "strings"
14 | )
15 |
16 | // Route stores information to match a request and build URLs.
17 | type Route struct {
18 | // Request handler for the route.
19 | handler http.Handler
20 | // If true, this route never matches: it is only used to build URLs.
21 | buildOnly bool
22 | // The name used to build URLs.
23 | name string
24 | // Error resulted from building a route.
25 | err error
26 |
27 | // "global" reference to all named routes
28 | namedRoutes map[string]*Route
29 |
30 | // config possibly passed in from `Router`
31 | routeConf
32 | }
33 |
34 | // SkipClean reports whether path cleaning is enabled for this route via
35 | // Router.SkipClean.
36 | func (r *Route) SkipClean() bool {
37 | return r.skipClean
38 | }
39 |
40 | // Match matches the route against the request.
41 | func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
42 | if r.buildOnly || r.err != nil {
43 | return false
44 | }
45 |
46 | var matchErr error
47 |
48 | // Match everything.
49 | for _, m := range r.matchers {
50 | if matched := m.Match(req, match); !matched {
51 | if _, ok := m.(methodMatcher); ok {
52 | matchErr = ErrMethodMismatch
53 | continue
54 | }
55 |
56 | // Ignore ErrNotFound errors. These errors arise from match call
57 | // to Subrouters.
58 | //
59 | // This prevents subsequent matching subrouters from failing to
60 | // run middleware. If not ignored, the middleware would see a
61 | // non-nil MatchErr and be skipped, even when there was a
62 | // matching route.
63 | if match.MatchErr == ErrNotFound {
64 | match.MatchErr = nil
65 | }
66 |
67 | matchErr = nil
68 | return false
69 | }
70 | }
71 |
72 | if matchErr != nil {
73 | match.MatchErr = matchErr
74 | return false
75 | }
76 |
77 | if match.MatchErr == ErrMethodMismatch && r.handler != nil {
78 | // We found a route which matches request method, clear MatchErr
79 | match.MatchErr = nil
80 | // Then override the mis-matched handler
81 | match.Handler = r.handler
82 | }
83 |
84 | // Yay, we have a match. Let's collect some info about it.
85 | if match.Route == nil {
86 | match.Route = r
87 | }
88 | if match.Handler == nil {
89 | match.Handler = r.handler
90 | }
91 | if match.Vars == nil {
92 | match.Vars = make(map[string]string)
93 | }
94 |
95 | // Set variables.
96 | r.regexp.setMatch(req, match, r)
97 | return true
98 | }
99 |
100 | // ----------------------------------------------------------------------------
101 | // Route attributes
102 | // ----------------------------------------------------------------------------
103 |
104 | // GetError returns an error resulted from building the route, if any.
105 | func (r *Route) GetError() error {
106 | return r.err
107 | }
108 |
109 | // BuildOnly sets the route to never match: it is only used to build URLs.
110 | func (r *Route) BuildOnly() *Route {
111 | r.buildOnly = true
112 | return r
113 | }
114 |
115 | // Handler --------------------------------------------------------------------
116 |
117 | // Handler sets a handler for the route.
118 | func (r *Route) Handler(handler http.Handler) *Route {
119 | if r.err == nil {
120 | r.handler = handler
121 | }
122 | return r
123 | }
124 |
125 | // HandlerFunc sets a handler function for the route.
126 | func (r *Route) HandlerFunc(f func(http.ResponseWriter, *http.Request)) *Route {
127 | return r.Handler(http.HandlerFunc(f))
128 | }
129 |
130 | // GetHandler returns the handler for the route, if any.
131 | func (r *Route) GetHandler() http.Handler {
132 | return r.handler
133 | }
134 |
135 | // Name -----------------------------------------------------------------------
136 |
137 | // Name sets the name for the route, used to build URLs.
138 | // It is an error to call Name more than once on a route.
139 | func (r *Route) Name(name string) *Route {
140 | if r.name != "" {
141 | r.err = fmt.Errorf("mux: route already has name %q, can't set %q",
142 | r.name, name)
143 | }
144 | if r.err == nil {
145 | r.name = name
146 | r.namedRoutes[name] = r
147 | }
148 | return r
149 | }
150 |
151 | // GetName returns the name for the route, if any.
152 | func (r *Route) GetName() string {
153 | return r.name
154 | }
155 |
156 | // ----------------------------------------------------------------------------
157 | // Matchers
158 | // ----------------------------------------------------------------------------
159 |
160 | // matcher types try to match a request.
161 | type matcher interface {
162 | Match(*http.Request, *RouteMatch) bool
163 | }
164 |
165 | // addMatcher adds a matcher to the route.
166 | func (r *Route) addMatcher(m matcher) *Route {
167 | if r.err == nil {
168 | r.matchers = append(r.matchers, m)
169 | }
170 | return r
171 | }
172 |
173 | // addRegexpMatcher adds a host or path matcher and builder to a route.
174 | func (r *Route) addRegexpMatcher(tpl string, typ regexpType) error {
175 | if r.err != nil {
176 | return r.err
177 | }
178 | if typ == regexpTypePath || typ == regexpTypePrefix {
179 | if len(tpl) > 0 && tpl[0] != '/' {
180 | return fmt.Errorf("mux: path must start with a slash, got %q", tpl)
181 | }
182 | if r.regexp.path != nil {
183 | tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl
184 | }
185 | }
186 | rr, err := newRouteRegexp(tpl, typ, routeRegexpOptions{
187 | strictSlash: r.strictSlash,
188 | useEncodedPath: r.useEncodedPath,
189 | })
190 | if err != nil {
191 | return err
192 | }
193 | for _, q := range r.regexp.queries {
194 | if err = uniqueVars(rr.varsN, q.varsN); err != nil {
195 | return err
196 | }
197 | }
198 | if typ == regexpTypeHost {
199 | if r.regexp.path != nil {
200 | if err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil {
201 | return err
202 | }
203 | }
204 | r.regexp.host = rr
205 | } else {
206 | if r.regexp.host != nil {
207 | if err = uniqueVars(rr.varsN, r.regexp.host.varsN); err != nil {
208 | return err
209 | }
210 | }
211 | if typ == regexpTypeQuery {
212 | r.regexp.queries = append(r.regexp.queries, rr)
213 | } else {
214 | r.regexp.path = rr
215 | }
216 | }
217 | r.addMatcher(rr)
218 | return nil
219 | }
220 |
221 | // Headers --------------------------------------------------------------------
222 |
223 | // headerMatcher matches the request against header values.
224 | type headerMatcher map[string]string
225 |
226 | func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool {
227 | return matchMapWithString(m, r.Header, true)
228 | }
229 |
230 | // Headers adds a matcher for request header values.
231 | // It accepts a sequence of key/value pairs to be matched. For example:
232 | //
233 | // r := mux.NewRouter()
234 | // r.Headers("Content-Type", "application/json",
235 | // "X-Requested-With", "XMLHttpRequest")
236 | //
237 | // The above route will only match if both request header values match.
238 | // If the value is an empty string, it will match any value if the key is set.
239 | func (r *Route) Headers(pairs ...string) *Route {
240 | if r.err == nil {
241 | var headers map[string]string
242 | headers, r.err = mapFromPairsToString(pairs...)
243 | return r.addMatcher(headerMatcher(headers))
244 | }
245 | return r
246 | }
247 |
248 | // headerRegexMatcher matches the request against the route given a regex for the header
249 | type headerRegexMatcher map[string]*regexp.Regexp
250 |
251 | func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool {
252 | return matchMapWithRegex(m, r.Header, true)
253 | }
254 |
255 | // HeadersRegexp accepts a sequence of key/value pairs, where the value has regex
256 | // support. For example:
257 | //
258 | // r := mux.NewRouter()
259 | // r.HeadersRegexp("Content-Type", "application/(text|json)",
260 | // "X-Requested-With", "XMLHttpRequest")
261 | //
262 | // The above route will only match if both the request header matches both regular expressions.
263 | // If the value is an empty string, it will match any value if the key is set.
264 | // Use the start and end of string anchors (^ and $) to match an exact value.
265 | func (r *Route) HeadersRegexp(pairs ...string) *Route {
266 | if r.err == nil {
267 | var headers map[string]*regexp.Regexp
268 | headers, r.err = mapFromPairsToRegex(pairs...)
269 | return r.addMatcher(headerRegexMatcher(headers))
270 | }
271 | return r
272 | }
273 |
274 | // Host -----------------------------------------------------------------------
275 |
276 | // Host adds a matcher for the URL host.
277 | // It accepts a template with zero or more URL variables enclosed by {}.
278 | // Variables can define an optional regexp pattern to be matched:
279 | //
280 | // - {name} matches anything until the next dot.
281 | //
282 | // - {name:pattern} matches the given regexp pattern.
283 | //
284 | // For example:
285 | //
286 | // r := mux.NewRouter()
287 | // r.Host("www.example.com")
288 | // r.Host("{subdomain}.domain.com")
289 | // r.Host("{subdomain:[a-z]+}.domain.com")
290 | //
291 | // Variable names must be unique in a given route. They can be retrieved
292 | // calling mux.Vars(request).
293 | func (r *Route) Host(tpl string) *Route {
294 | r.err = r.addRegexpMatcher(tpl, regexpTypeHost)
295 | return r
296 | }
297 |
298 | // MatcherFunc ----------------------------------------------------------------
299 |
300 | // MatcherFunc is the function signature used by custom matchers.
301 | type MatcherFunc func(*http.Request, *RouteMatch) bool
302 |
303 | // Match returns the match for a given request.
304 | func (m MatcherFunc) Match(r *http.Request, match *RouteMatch) bool {
305 | return m(r, match)
306 | }
307 |
308 | // MatcherFunc adds a custom function to be used as request matcher.
309 | func (r *Route) MatcherFunc(f MatcherFunc) *Route {
310 | return r.addMatcher(f)
311 | }
312 |
313 | // Methods --------------------------------------------------------------------
314 |
315 | // methodMatcher matches the request against HTTP methods.
316 | type methodMatcher []string
317 |
318 | func (m methodMatcher) Match(r *http.Request, match *RouteMatch) bool {
319 | return matchInArray(m, r.Method)
320 | }
321 |
322 | // Methods adds a matcher for HTTP methods.
323 | // It accepts a sequence of one or more methods to be matched, e.g.:
324 | // "GET", "POST", "PUT".
325 | func (r *Route) Methods(methods ...string) *Route {
326 | for k, v := range methods {
327 | methods[k] = strings.ToUpper(v)
328 | }
329 | return r.addMatcher(methodMatcher(methods))
330 | }
331 |
332 | // Path -----------------------------------------------------------------------
333 |
334 | // Path adds a matcher for the URL path.
335 | // It accepts a template with zero or more URL variables enclosed by {}. The
336 | // template must start with a "/".
337 | // Variables can define an optional regexp pattern to be matched:
338 | //
339 | // - {name} matches anything until the next slash.
340 | //
341 | // - {name:pattern} matches the given regexp pattern.
342 | //
343 | // For example:
344 | //
345 | // r := mux.NewRouter()
346 | // r.Path("/products/").Handler(ProductsHandler)
347 | // r.Path("/products/{key}").Handler(ProductsHandler)
348 | // r.Path("/articles/{category}/{id:[0-9]+}").
349 | // Handler(ArticleHandler)
350 | //
351 | // Variable names must be unique in a given route. They can be retrieved
352 | // calling mux.Vars(request).
353 | func (r *Route) Path(tpl string) *Route {
354 | r.err = r.addRegexpMatcher(tpl, regexpTypePath)
355 | return r
356 | }
357 |
358 | // PathPrefix -----------------------------------------------------------------
359 |
360 | // PathPrefix adds a matcher for the URL path prefix. This matches if the given
361 | // template is a prefix of the full URL path. See Route.Path() for details on
362 | // the tpl argument.
363 | //
364 | // Note that it does not treat slashes specially ("/foobar/" will be matched by
365 | // the prefix "/foo") so you may want to use a trailing slash here.
366 | //
367 | // Also note that the setting of Router.StrictSlash() has no effect on routes
368 | // with a PathPrefix matcher.
369 | func (r *Route) PathPrefix(tpl string) *Route {
370 | r.err = r.addRegexpMatcher(tpl, regexpTypePrefix)
371 | return r
372 | }
373 |
374 | // Query ----------------------------------------------------------------------
375 |
376 | // Queries adds a matcher for URL query values.
377 | // It accepts a sequence of key/value pairs. Values may define variables.
378 | // For example:
379 | //
380 | // r := mux.NewRouter()
381 | // r.Queries("foo", "bar", "id", "{id:[0-9]+}")
382 | //
383 | // The above route will only match if the URL contains the defined queries
384 | // values, e.g.: ?foo=bar&id=42.
385 | //
386 | // If the value is an empty string, it will match any value if the key is set.
387 | //
388 | // Variables can define an optional regexp pattern to be matched:
389 | //
390 | // - {name} matches anything until the next slash.
391 | //
392 | // - {name:pattern} matches the given regexp pattern.
393 | func (r *Route) Queries(pairs ...string) *Route {
394 | length := len(pairs)
395 | if length%2 != 0 {
396 | r.err = fmt.Errorf(
397 | "mux: number of parameters must be multiple of 2, got %v", pairs)
398 | return nil
399 | }
400 | for i := 0; i < length; i += 2 {
401 | if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], regexpTypeQuery); r.err != nil {
402 | return r
403 | }
404 | }
405 |
406 | return r
407 | }
408 |
409 | // Schemes --------------------------------------------------------------------
410 |
411 | // schemeMatcher matches the request against URL schemes.
412 | type schemeMatcher []string
413 |
414 | func (m schemeMatcher) Match(r *http.Request, match *RouteMatch) bool {
415 | scheme := r.URL.Scheme
416 | // https://golang.org/pkg/net/http/#Request
417 | // "For [most] server requests, fields other than Path and RawQuery will be
418 | // empty."
419 | // Since we're an http muxer, the scheme is either going to be http or https
420 | // though, so we can just set it based on the tls termination state.
421 | if scheme == "" {
422 | if r.TLS == nil {
423 | scheme = "http"
424 | } else {
425 | scheme = "https"
426 | }
427 | }
428 | return matchInArray(m, scheme)
429 | }
430 |
431 | // Schemes adds a matcher for URL schemes.
432 | // It accepts a sequence of schemes to be matched, e.g.: "http", "https".
433 | // If the request's URL has a scheme set, it will be matched against.
434 | // Generally, the URL scheme will only be set if a previous handler set it,
435 | // such as the ProxyHeaders handler from gorilla/handlers.
436 | // If unset, the scheme will be determined based on the request's TLS
437 | // termination state.
438 | // The first argument to Schemes will be used when constructing a route URL.
439 | func (r *Route) Schemes(schemes ...string) *Route {
440 | for k, v := range schemes {
441 | schemes[k] = strings.ToLower(v)
442 | }
443 | if len(schemes) > 0 {
444 | r.buildScheme = schemes[0]
445 | }
446 | return r.addMatcher(schemeMatcher(schemes))
447 | }
448 |
449 | // BuildVarsFunc --------------------------------------------------------------
450 |
451 | // BuildVarsFunc is the function signature used by custom build variable
452 | // functions (which can modify route variables before a route's URL is built).
453 | type BuildVarsFunc func(map[string]string) map[string]string
454 |
455 | // BuildVarsFunc adds a custom function to be used to modify build variables
456 | // before a route's URL is built.
457 | func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route {
458 | if r.buildVarsFunc != nil {
459 | // compose the old and new functions
460 | old := r.buildVarsFunc
461 | r.buildVarsFunc = func(m map[string]string) map[string]string {
462 | return f(old(m))
463 | }
464 | } else {
465 | r.buildVarsFunc = f
466 | }
467 | return r
468 | }
469 |
470 | // Subrouter ------------------------------------------------------------------
471 |
472 | // Subrouter creates a subrouter for the route.
473 | //
474 | // It will test the inner routes only if the parent route matched. For example:
475 | //
476 | // r := mux.NewRouter()
477 | // s := r.Host("www.example.com").Subrouter()
478 | // s.HandleFunc("/products/", ProductsHandler)
479 | // s.HandleFunc("/products/{key}", ProductHandler)
480 | // s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
481 | //
482 | // Here, the routes registered in the subrouter won't be tested if the host
483 | // doesn't match.
484 | func (r *Route) Subrouter() *Router {
485 | // initialize a subrouter with a copy of the parent route's configuration
486 | router := &Router{routeConf: copyRouteConf(r.routeConf), namedRoutes: r.namedRoutes}
487 | r.addMatcher(router)
488 | return router
489 | }
490 |
491 | // ----------------------------------------------------------------------------
492 | // URL building
493 | // ----------------------------------------------------------------------------
494 |
495 | // URL builds a URL for the route.
496 | //
497 | // It accepts a sequence of key/value pairs for the route variables. For
498 | // example, given this route:
499 | //
500 | // r := mux.NewRouter()
501 | // r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
502 | // Name("article")
503 | //
504 | // ...a URL for it can be built using:
505 | //
506 | // url, err := r.Get("article").URL("category", "technology", "id", "42")
507 | //
508 | // ...which will return an url.URL with the following path:
509 | //
510 | // "/articles/technology/42"
511 | //
512 | // This also works for host variables:
513 | //
514 | // r := mux.NewRouter()
515 | // r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
516 | // Host("{subdomain}.domain.com").
517 | // Name("article")
518 | //
519 | // // url.String() will be "http://news.domain.com/articles/technology/42"
520 | // url, err := r.Get("article").URL("subdomain", "news",
521 | // "category", "technology",
522 | // "id", "42")
523 | //
524 | // The scheme of the resulting url will be the first argument that was passed to Schemes:
525 | //
526 | // // url.String() will be "https://example.com"
527 | // r := mux.NewRouter()
528 | // url, err := r.Host("example.com")
529 | // .Schemes("https", "http").URL()
530 | //
531 | // All variables defined in the route are required, and their values must
532 | // conform to the corresponding patterns.
533 | func (r *Route) URL(pairs ...string) (*url.URL, error) {
534 | if r.err != nil {
535 | return nil, r.err
536 | }
537 | values, err := r.prepareVars(pairs...)
538 | if err != nil {
539 | return nil, err
540 | }
541 | var scheme, host, path string
542 | queries := make([]string, 0, len(r.regexp.queries))
543 | if r.regexp.host != nil {
544 | if host, err = r.regexp.host.url(values); err != nil {
545 | return nil, err
546 | }
547 | scheme = "http"
548 | if r.buildScheme != "" {
549 | scheme = r.buildScheme
550 | }
551 | }
552 | if r.regexp.path != nil {
553 | if path, err = r.regexp.path.url(values); err != nil {
554 | return nil, err
555 | }
556 | }
557 | for _, q := range r.regexp.queries {
558 | var query string
559 | if query, err = q.url(values); err != nil {
560 | return nil, err
561 | }
562 | queries = append(queries, query)
563 | }
564 | return &url.URL{
565 | Scheme: scheme,
566 | Host: host,
567 | Path: path,
568 | RawQuery: strings.Join(queries, "&"),
569 | }, nil
570 | }
571 |
572 | // URLHost builds the host part of the URL for a route. See Route.URL().
573 | //
574 | // The route must have a host defined.
575 | func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
576 | if r.err != nil {
577 | return nil, r.err
578 | }
579 | if r.regexp.host == nil {
580 | return nil, errors.New("mux: route doesn't have a host")
581 | }
582 | values, err := r.prepareVars(pairs...)
583 | if err != nil {
584 | return nil, err
585 | }
586 | host, err := r.regexp.host.url(values)
587 | if err != nil {
588 | return nil, err
589 | }
590 | u := &url.URL{
591 | Scheme: "http",
592 | Host: host,
593 | }
594 | if r.buildScheme != "" {
595 | u.Scheme = r.buildScheme
596 | }
597 | return u, nil
598 | }
599 |
600 | // URLPath builds the path part of the URL for a route. See Route.URL().
601 | //
602 | // The route must have a path defined.
603 | func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
604 | if r.err != nil {
605 | return nil, r.err
606 | }
607 | if r.regexp.path == nil {
608 | return nil, errors.New("mux: route doesn't have a path")
609 | }
610 | values, err := r.prepareVars(pairs...)
611 | if err != nil {
612 | return nil, err
613 | }
614 | path, err := r.regexp.path.url(values)
615 | if err != nil {
616 | return nil, err
617 | }
618 | return &url.URL{
619 | Path: path,
620 | }, nil
621 | }
622 |
623 | // GetPathTemplate returns the template used to build the
624 | // route match.
625 | // This is useful for building simple REST API documentation and for instrumentation
626 | // against third-party services.
627 | // An error will be returned if the route does not define a path.
628 | func (r *Route) GetPathTemplate() (string, error) {
629 | if r.err != nil {
630 | return "", r.err
631 | }
632 | if r.regexp.path == nil {
633 | return "", errors.New("mux: route doesn't have a path")
634 | }
635 | return r.regexp.path.template, nil
636 | }
637 |
638 | // GetPathRegexp returns the expanded regular expression used to match route path.
639 | // This is useful for building simple REST API documentation and for instrumentation
640 | // against third-party services.
641 | // An error will be returned if the route does not define a path.
642 | func (r *Route) GetPathRegexp() (string, error) {
643 | if r.err != nil {
644 | return "", r.err
645 | }
646 | if r.regexp.path == nil {
647 | return "", errors.New("mux: route does not have a path")
648 | }
649 | return r.regexp.path.regexp.String(), nil
650 | }
651 |
652 | // GetQueriesRegexp returns the expanded regular expressions used to match the
653 | // route queries.
654 | // This is useful for building simple REST API documentation and for instrumentation
655 | // against third-party services.
656 | // An error will be returned if the route does not have queries.
657 | func (r *Route) GetQueriesRegexp() ([]string, error) {
658 | if r.err != nil {
659 | return nil, r.err
660 | }
661 | if r.regexp.queries == nil {
662 | return nil, errors.New("mux: route doesn't have queries")
663 | }
664 | queries := make([]string, 0, len(r.regexp.queries))
665 | for _, query := range r.regexp.queries {
666 | queries = append(queries, query.regexp.String())
667 | }
668 | return queries, nil
669 | }
670 |
671 | // GetQueriesTemplates returns the templates used to build the
672 | // query matching.
673 | // This is useful for building simple REST API documentation and for instrumentation
674 | // against third-party services.
675 | // An error will be returned if the route does not define queries.
676 | func (r *Route) GetQueriesTemplates() ([]string, error) {
677 | if r.err != nil {
678 | return nil, r.err
679 | }
680 | if r.regexp.queries == nil {
681 | return nil, errors.New("mux: route doesn't have queries")
682 | }
683 | queries := make([]string, 0, len(r.regexp.queries))
684 | for _, query := range r.regexp.queries {
685 | queries = append(queries, query.template)
686 | }
687 | return queries, nil
688 | }
689 |
690 | // GetMethods returns the methods the route matches against
691 | // This is useful for building simple REST API documentation and for instrumentation
692 | // against third-party services.
693 | // An error will be returned if route does not have methods.
694 | func (r *Route) GetMethods() ([]string, error) {
695 | if r.err != nil {
696 | return nil, r.err
697 | }
698 | for _, m := range r.matchers {
699 | if methods, ok := m.(methodMatcher); ok {
700 | return []string(methods), nil
701 | }
702 | }
703 | return nil, errors.New("mux: route doesn't have methods")
704 | }
705 |
706 | // GetHostTemplate returns the template used to build the
707 | // route match.
708 | // This is useful for building simple REST API documentation and for instrumentation
709 | // against third-party services.
710 | // An error will be returned if the route does not define a host.
711 | func (r *Route) GetHostTemplate() (string, error) {
712 | if r.err != nil {
713 | return "", r.err
714 | }
715 | if r.regexp.host == nil {
716 | return "", errors.New("mux: route doesn't have a host")
717 | }
718 | return r.regexp.host.template, nil
719 | }
720 |
721 | // prepareVars converts the route variable pairs into a map. If the route has a
722 | // BuildVarsFunc, it is invoked.
723 | func (r *Route) prepareVars(pairs ...string) (map[string]string, error) {
724 | m, err := mapFromPairsToString(pairs...)
725 | if err != nil {
726 | return nil, err
727 | }
728 | return r.buildVars(m), nil
729 | }
730 |
731 | func (r *Route) buildVars(m map[string]string) map[string]string {
732 | if r.buildVarsFunc != nil {
733 | m = r.buildVarsFunc(m)
734 | }
735 | return m
736 | }
737 |
--------------------------------------------------------------------------------
/23mymodules/vendor/github.com/gorilla/mux/test_helpers.go:
--------------------------------------------------------------------------------
1 | // Copyright 2012 The Gorilla Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package mux
6 |
7 | import "net/http"
8 |
9 | // SetURLVars sets the URL variables for the given request, to be accessed via
10 | // mux.Vars for testing route behaviour. Arguments are not modified, a shallow
11 | // copy is returned.
12 | //
13 | // This API should only be used for testing purposes; it provides a way to
14 | // inject variables into the request context. Alternatively, URL variables
15 | // can be set by making a route that captures the required variables,
16 | // starting a server and sending the request to that server.
17 | func SetURLVars(r *http.Request, val map[string]string) *http.Request {
18 | return requestWithVars(r, val)
19 | }
20 |
--------------------------------------------------------------------------------
/23mymodules/vendor/modules.txt:
--------------------------------------------------------------------------------
1 | # github.com/gorilla/mux v1.8.0
2 | ## explicit; go 1.12
3 | github.com/gorilla/mux
4 |
--------------------------------------------------------------------------------
/24buildapi/buildapi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshchoudhary/golang/1a63628fe4bb1798a79c9319019d931e5ae179e1/24buildapi/buildapi
--------------------------------------------------------------------------------
/24buildapi/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/hiteshchoudhary/buildapi
2 |
3 | go 1.17
4 |
5 | require github.com/gorilla/mux v1.8.0 // indirect
6 |
--------------------------------------------------------------------------------
/24buildapi/go.sum:
--------------------------------------------------------------------------------
1 | github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
2 | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
3 |
--------------------------------------------------------------------------------
/24buildapi/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "log"
7 | "math/rand"
8 | "net/http"
9 | "strconv"
10 | "time"
11 |
12 | "github.com/gorilla/mux"
13 | )
14 |
15 | // Model for course - file
16 | type Course struct {
17 | CourseId string `json:"courseid"`
18 | CourseName string `json:"coursename"`
19 | CoursePrice int `json:"price"`
20 | Author *Author `json:"author"`
21 | }
22 |
23 | type Author struct {
24 | Fullname string `json:"fullname"`
25 | Website string `json:"website"`
26 | }
27 |
28 | //fake DB
29 | var courses []Course
30 |
31 | // middleware, helper - file
32 | func (c *Course) IsEmpty() bool {
33 | // return c.CourseId == "" && c.CourseName == ""
34 | return c.CourseName == ""
35 | }
36 |
37 | func main() {
38 | fmt.Println("API - LearnCodeOnline.in")
39 | r := mux.NewRouter()
40 |
41 | //seeding
42 | courses = append(courses, Course{CourseId: "2", CourseName: "ReactJS", CoursePrice: 299, Author: &Author{Fullname: "Hitesh Choudhary", Website: "lco.dev"}})
43 | courses = append(courses, Course{CourseId: "4", CourseName: "MERN Stack", CoursePrice: 199, Author: &Author{Fullname: "Hitesh Choudhary", Website: "go.dev"}})
44 |
45 | //routing
46 | r.HandleFunc("/", serveHome).Methods("GET")
47 | r.HandleFunc("/courses", getAllCourses).Methods("GET")
48 | r.HandleFunc("/course/{id}", getOneCourse).Methods("GET")
49 | r.HandleFunc("/course", createOneCourse).Methods("POST")
50 | r.HandleFunc("/course/{id}", updateOneCourse).Methods("PUT")
51 | r.HandleFunc("/course/{id}", deleteOneCourse).Methods("DELETE")
52 |
53 | // listen to a port
54 | log.Fatal(http.ListenAndServe(":4000", r))
55 | }
56 |
57 | //controllers - file
58 |
59 | // serve home route
60 |
61 | func serveHome(w http.ResponseWriter, r *http.Request) {
62 | w.Write([]byte("Welcome to API by LearnCodeOnline
"))
63 | }
64 |
65 | func getAllCourses(w http.ResponseWriter, r *http.Request) {
66 | fmt.Println("Get all courses")
67 | w.Header().Set("Content-Type", "applicatioan/json")
68 | json.NewEncoder(w).Encode(courses)
69 | }
70 |
71 | func getOneCourse(w http.ResponseWriter, r *http.Request) {
72 | fmt.Println("Get one course")
73 | w.Header().Set("Content-Type", "applicatioan/json")
74 |
75 | // grab id from request
76 | params := mux.Vars(r)
77 |
78 | // loop through courses, find matching id and return the response
79 | for _, course := range courses {
80 | if course.CourseId == params["id"] {
81 | json.NewEncoder(w).Encode(course)
82 | return
83 | }
84 | }
85 | json.NewEncoder(w).Encode("No Course found with given id")
86 | return
87 | }
88 |
89 | func createOneCourse(w http.ResponseWriter, r *http.Request) {
90 | fmt.Println("Create one course")
91 | w.Header().Set("Content-Type", "applicatioan/json")
92 |
93 | // what if: body is empty
94 | if r.Body == nil {
95 | json.NewEncoder(w).Encode("Please send some data")
96 | }
97 |
98 | // what about - {}
99 |
100 | var course Course
101 | _ = json.NewDecoder(r.Body).Decode(&course)
102 | if course.IsEmpty() {
103 | json.NewEncoder(w).Encode("No data inside JSON")
104 | return
105 | }
106 |
107 | //TODO: check only if title is duplicate
108 | // loop, title matches with course.coursename, JSON
109 |
110 | // generate unique id, string
111 | // append course into courses
112 |
113 | rand.Seed(time.Now().UnixNano())
114 | course.CourseId = strconv.Itoa(rand.Intn(100))
115 | courses = append(courses, course)
116 | json.NewEncoder(w).Encode(course)
117 | return
118 |
119 | }
120 |
121 | func updateOneCourse(w http.ResponseWriter, r *http.Request) {
122 | fmt.Println("Update one course")
123 | w.Header().Set("Content-Type", "applicatioan/json")
124 |
125 | // first - grab id from req
126 | params := mux.Vars(r)
127 |
128 | // loop, id, remove, add with my ID
129 |
130 | for index, course := range courses {
131 | if course.CourseId == params["id"] {
132 | courses = append(courses[:index], courses[index+1:]...)
133 | var course Course
134 | _ = json.NewDecoder(r.Body).Decode(&course)
135 | course.CourseId = params["id"]
136 | courses = append(courses, course)
137 | json.NewEncoder(w).Encode(course)
138 | return
139 | }
140 | }
141 | //TODO: send a response when id is not found
142 | }
143 |
144 | func deleteOneCourse(w http.ResponseWriter, r *http.Request) {
145 | fmt.Println("Delete one course")
146 | w.Header().Set("Content-Type", "applicatioan/json")
147 |
148 | params := mux.Vars(r)
149 |
150 | //loop, id, remove (index, index+1)
151 |
152 | for index, course := range courses {
153 | if course.CourseId == params["id"] {
154 | courses = append(courses[:index], courses[index+1:]...)
155 | // TODO: send a confirm or deny response
156 | break
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/25mongoapi/controller/controller.go:
--------------------------------------------------------------------------------
1 | package controller
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "fmt"
7 | "log"
8 | "net/http"
9 |
10 | "github.com/gorilla/mux"
11 | "github.com/hiteshchoudhary/mongoapi/model"
12 | "go.mongodb.org/mongo-driver/bson"
13 | "go.mongodb.org/mongo-driver/bson/primitive"
14 | "go.mongodb.org/mongo-driver/mongo"
15 | "go.mongodb.org/mongo-driver/mongo/options"
16 | )
17 |
18 | const connectionString = "mongodb+srv://learncodeonline:hitesh@cluster0.humov.mongodb.net/myFirstDatabase?retryWrites=true&w=majority"
19 | const dbName = "netflix"
20 | const colName = "watchlist"
21 |
22 | //MOST IMPORTANT
23 | var collection *mongo.Collection
24 |
25 | // connect with monogoDB
26 |
27 | func init() {
28 | //client option
29 | clientOption := options.Client().ApplyURI(connectionString)
30 |
31 | //connect to mongodb
32 | client, err := mongo.Connect(context.TODO(), clientOption)
33 |
34 | if err != nil {
35 | log.Fatal(err)
36 | }
37 | fmt.Println("MongoDB connection success")
38 |
39 | collection = client.Database(dbName).Collection(colName)
40 |
41 | //collection instance
42 | fmt.Println("Collection instance is ready")
43 | }
44 |
45 | // MONGODB helpers - file
46 |
47 | // insert 1 record
48 | func insertOneMovie(movie model.Netflix) {
49 | inserted, err := collection.InsertOne(context.Background(), movie)
50 |
51 | if err != nil {
52 | log.Fatal(err)
53 | }
54 | fmt.Println("Inserted 1 movie in db with id: ", inserted.InsertedID)
55 | }
56 |
57 | // update 1 record
58 | func updateOneMovie(movieId string) {
59 | id, _ := primitive.ObjectIDFromHex(movieId)
60 | filter := bson.M{"_id": id}
61 | update := bson.M{"$set": bson.M{"watched": true}}
62 |
63 | result, err := collection.UpdateOne(context.Background(), filter, update)
64 | if err != nil {
65 | log.Fatal(err)
66 | }
67 |
68 | fmt.Println("modified count: ", result.ModifiedCount)
69 | }
70 |
71 | // delete 1 record
72 | func deleteOneMovie(movieId string) {
73 | id, _ := primitive.ObjectIDFromHex(movieId)
74 | filter := bson.M{"_id": id}
75 | deleteCount, err := collection.DeleteOne(context.Background(), filter)
76 |
77 | if err != nil {
78 | log.Fatal(err)
79 | }
80 | fmt.Println("MOvie got delete with delete count: ", deleteCount)
81 | }
82 |
83 | // delete all records from mongodb
84 | func deleteAllMovie() int64 {
85 |
86 | deleteResult, err := collection.DeleteMany(context.Background(), bson.D{{}}, nil)
87 |
88 | if err != nil {
89 | log.Fatal(err)
90 | }
91 |
92 | fmt.Println("NUmber of movies delete: ", deleteResult.DeletedCount)
93 | return deleteResult.DeletedCount
94 | }
95 |
96 | // get all movies from database
97 |
98 | func getAllMovies() []primitive.M {
99 | cur, err := collection.Find(context.Background(), bson.D{{}})
100 | if err != nil {
101 | log.Fatal(err)
102 | }
103 |
104 | var movies []primitive.M
105 |
106 | for cur.Next(context.Background()) {
107 | var movie bson.M
108 | err := cur.Decode(&movie)
109 | if err != nil {
110 | log.Fatal(err)
111 | }
112 | movies = append(movies, movie)
113 | }
114 |
115 | defer cur.Close(context.Background())
116 | return movies
117 | }
118 |
119 | // Actual controller - file
120 |
121 | func GetMyAllMovies(w http.ResponseWriter, r *http.Request) {
122 | w.Header().Set("Content-Type", "application/x-www-form-urlencode")
123 | allMovies := getAllMovies()
124 | json.NewEncoder(w).Encode(allMovies)
125 | }
126 |
127 | func CreateMovie(w http.ResponseWriter, r *http.Request) {
128 | w.Header().Set("Content-Type", "application/x-www-form-urlencode")
129 | w.Header().Set("Allow-Control-Allow-Methods", "POST")
130 |
131 | var movie model.Netflix
132 | _ = json.NewDecoder(r.Body).Decode(&movie)
133 | insertOneMovie(movie)
134 | json.NewEncoder(w).Encode(movie)
135 |
136 | }
137 |
138 | func MarkAsWatched(w http.ResponseWriter, r *http.Request) {
139 | w.Header().Set("Content-Type", "application/x-www-form-urlencode")
140 | w.Header().Set("Allow-Control-Allow-Methods", "PUT")
141 |
142 | params := mux.Vars(r)
143 | updateOneMovie(params["id"])
144 | json.NewEncoder(w).Encode(params["id"])
145 | }
146 |
147 | func DeleteAMovie(w http.ResponseWriter, r *http.Request) {
148 | w.Header().Set("Content-Type", "application/x-www-form-urlencode")
149 | w.Header().Set("Allow-Control-Allow-Methods", "DELETE")
150 |
151 | params := mux.Vars(r)
152 | deleteOneMovie(params["id"])
153 | json.NewEncoder(w).Encode(params["id"])
154 | }
155 |
156 | func DeleteAllMovies(w http.ResponseWriter, r *http.Request) {
157 | w.Header().Set("Content-Type", "application/x-www-form-urlencode")
158 | w.Header().Set("Allow-Control-Allow-Methods", "DELETE")
159 |
160 | count := deleteAllMovie()
161 | json.NewEncoder(w).Encode(count)
162 | }
163 |
--------------------------------------------------------------------------------
/25mongoapi/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/hiteshchoudhary/mongoapi
2 |
3 | go 1.17
4 |
5 | require (
6 | github.com/BurntSushi/toml v0.3.1 // indirect
7 | github.com/go-stack/stack v1.8.0 // indirect
8 | github.com/golang/snappy v0.0.1 // indirect
9 | github.com/google/go-cmp v0.5.5 // indirect
10 | github.com/gorilla/mux v1.8.0 // indirect
11 | github.com/klauspost/compress v1.9.5 // indirect
12 | github.com/pkg/errors v0.9.1 // indirect
13 | github.com/sergi/go-diff v1.1.0 // indirect
14 | github.com/xdg-go/pbkdf2 v1.0.0 // indirect
15 | github.com/xdg-go/scram v1.0.2 // indirect
16 | github.com/xdg-go/stringprep v1.0.2 // indirect
17 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
18 | go.mongodb.org/mongo-driver v1.7.1 // indirect
19 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
20 | golang.org/x/mod v0.4.2 // indirect
21 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
22 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect
23 | golang.org/x/text v0.3.6 // indirect
24 | golang.org/x/tools v0.1.6-0.20210802203754-9b21a8868e16 // indirect
25 | golang.org/x/tools/gopls v0.7.1 // indirect
26 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
27 | honnef.co/go/tools v0.2.0 // indirect
28 | mvdan.cc/gofumpt v0.1.1 // indirect
29 | mvdan.cc/xurls/v2 v2.2.0 // indirect
30 | )
31 |
--------------------------------------------------------------------------------
/25mongoapi/go.sum:
--------------------------------------------------------------------------------
1 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5 | github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
6 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
7 | github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
8 | github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
9 | github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
10 | github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
11 | github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
12 | github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=
13 | github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
14 | github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
15 | github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
16 | github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=
17 | github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=
18 | github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
19 | github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
20 | github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
21 | github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=
22 | github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
23 | github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
24 | github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
25 | github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
26 | github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
27 | github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
28 | github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
29 | github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
30 | github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
31 | github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
32 | github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
33 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
34 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
35 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
36 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
37 | github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
38 | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
39 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
40 | github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
41 | github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
42 | github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
43 | github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M=
44 | github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
45 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
46 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
47 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
48 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
49 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
50 | github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
51 | github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
52 | github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
53 | github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
54 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
55 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
56 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
57 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
58 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
59 | github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
60 | github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
61 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
62 | github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
63 | github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
64 | github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
65 | github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
66 | github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
67 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
68 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
69 | github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
70 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
71 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
72 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
73 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
74 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
75 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
76 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
77 | github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
78 | github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
79 | github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
80 | github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w=
81 | github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
82 | github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc=
83 | github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
84 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
85 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
86 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
87 | go.mongodb.org/mongo-driver v1.7.1 h1:jwqTeEM3x6L9xDXrCxN0Hbg7vdGfPBOTIkr0+/LYZDA=
88 | go.mongodb.org/mongo-driver v1.7.1/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8=
89 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
90 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
91 | golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
92 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
93 | golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
94 | golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
95 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
96 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
97 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
98 | golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
99 | golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
100 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
101 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
102 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
103 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
104 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
105 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
106 | golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
107 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
108 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
109 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
110 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
111 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
112 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
113 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
114 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
115 | golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
116 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
117 | golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
118 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
119 | golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
120 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
121 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
122 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
123 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
124 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
125 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
126 | golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
127 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
128 | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
129 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
130 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
131 | golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
132 | golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
133 | golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
134 | golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
135 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
136 | golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
137 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
138 | golang.org/x/tools v0.1.6-0.20210802203754-9b21a8868e16 h1:ZC/gVBZl8poJyKzWLxxlsmhayVGosF4mohR35szD5Bg=
139 | golang.org/x/tools v0.1.6-0.20210802203754-9b21a8868e16/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
140 | golang.org/x/tools/gopls v0.7.1 h1:Mh3Z8Xcoq3Zy7ksSlwDV/nzQSbjFf06A+L+F8YHq55U=
141 | golang.org/x/tools/gopls v0.7.1/go.mod h1:keTmqBxKJRaTbzntq7EG7w8Pa7OlOXVqm4rc6Z09gMU=
142 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
143 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
144 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
145 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
146 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
147 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
148 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
149 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
150 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
151 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
152 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
153 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
154 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
155 | honnef.co/go/tools v0.2.0 h1:ws8AfbgTX3oIczLPNPCu5166oBg9ST2vNs0rcht+mDE=
156 | honnef.co/go/tools v0.2.0/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
157 | mvdan.cc/gofumpt v0.1.1 h1:bi/1aS/5W00E2ny5q65w9SnKpWEF/UIOqDYBILpo9rA=
158 | mvdan.cc/gofumpt v0.1.1/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48=
159 | mvdan.cc/xurls/v2 v2.2.0 h1:NSZPykBXJFCetGZykLAxaL6SIpvbVy/UFEniIfHAa8A=
160 | mvdan.cc/xurls/v2 v2.2.0/go.mod h1:EV1RMtya9D6G5DMYPGD8zTQzaHet6Jh8gFlRgGRJeO8=
161 |
--------------------------------------------------------------------------------
/25mongoapi/main:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshchoudhary/golang/1a63628fe4bb1798a79c9319019d931e5ae179e1/25mongoapi/main
--------------------------------------------------------------------------------
/25mongoapi/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 |
8 | "github.com/hiteshchoudhary/mongoapi/router"
9 | )
10 |
11 | func main() {
12 | fmt.Println("MongoDB API")
13 | r := router.Router()
14 | fmt.Println("Server is getting started...")
15 | log.Fatal(http.ListenAndServe(":4000", r))
16 | fmt.Println("Listening at port 4000 ...")
17 | }
18 |
--------------------------------------------------------------------------------
/25mongoapi/model/models.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "go.mongodb.org/mongo-driver/bson/primitive"
5 | )
6 |
7 | type Netflix struct {
8 | ID primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
9 | Movie string `json:"movie,omitempty"`
10 | Watched bool `json:"watched,omitempty"`
11 | }
12 |
--------------------------------------------------------------------------------
/25mongoapi/router/router.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gorilla/mux"
5 | "github.com/hiteshchoudhary/mongoapi/controller"
6 | )
7 |
8 | func Router() *mux.Router {
9 | router := mux.NewRouter()
10 |
11 | router.HandleFunc("/api/movies", controller.GetMyAllMovies).Methods("GET")
12 | router.HandleFunc("/api/movie", controller.CreateMovie).Methods("POST")
13 | router.HandleFunc("/api/movie/{id}", controller.MarkAsWatched).Methods("PUT")
14 | router.HandleFunc("/api/movie/{id}", controller.DeleteAMovie).Methods("DELETE")
15 | router.HandleFunc("/api/deleteallmovie", controller.DeleteAllMovies).Methods("DELETE")
16 |
17 | return router
18 | }
19 |
--------------------------------------------------------------------------------
/26goroutines/go.mod:
--------------------------------------------------------------------------------
1 | module goroutines
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/26goroutines/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 | "sync"
7 | )
8 |
9 | var signals = []string{"test"}
10 |
11 | var wg sync.WaitGroup //pointer
12 | var mut sync.Mutex // pointer
13 |
14 | func main() {
15 | // go greeter("Hello")
16 | // greeter("world")
17 | websitelist := []string{
18 | "https://lco.dev",
19 | "https://go.dev",
20 | "https://google.com",
21 | "https://fb.com",
22 | "https://github.com",
23 | }
24 |
25 | for _, web := range websitelist {
26 | go getStatusCode(web)
27 | wg.Add(1)
28 | }
29 |
30 | wg.Wait()
31 | fmt.Println(signals)
32 | }
33 |
34 | // func greeter(s string) {
35 | // for i := 0; i < 6; i++ {
36 | // time.Sleep(3 * time.Millisecond)
37 | // fmt.Println(s)
38 | // }
39 | // }
40 |
41 | func getStatusCode(endpoint string) {
42 | defer wg.Done()
43 |
44 | res, err := http.Get(endpoint)
45 |
46 | if err != nil {
47 | fmt.Println("OOPS in endpoint")
48 | } else {
49 | mut.Lock()
50 | signals = append(signals, endpoint)
51 | mut.Unlock()
52 |
53 | fmt.Printf("%d status code for %s\n", res.StatusCode, endpoint)
54 |
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/27mutexAndAwaitGroups/go.mod:
--------------------------------------------------------------------------------
1 | module mutexandawaitgroups
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/27mutexAndAwaitGroups/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "sync"
6 | )
7 |
8 | func main() {
9 | fmt.Println("Race condition - LearnCodeonline.in")
10 |
11 | wg := &sync.WaitGroup{}
12 | mut := &sync.RWMutex{}
13 |
14 | var score = []int{0}
15 |
16 | wg.Add(3)
17 | go func(wg *sync.WaitGroup, m *sync.RWMutex) {
18 | fmt.Println("One R")
19 | mut.Lock()
20 | score = append(score, 1)
21 | mut.Unlock()
22 | wg.Done()
23 | }(wg, mut)
24 | //wg.Add(1)
25 | go func(wg *sync.WaitGroup, m *sync.RWMutex) {
26 | fmt.Println("Two R")
27 | mut.Lock()
28 | score = append(score, 2)
29 | mut.Unlock()
30 | wg.Done()
31 | }(wg, mut)
32 | go func(wg *sync.WaitGroup, m *sync.RWMutex) {
33 | fmt.Println("Three R")
34 | mut.Lock()
35 | score = append(score, 3)
36 | mut.Unlock()
37 | wg.Done()
38 | }(wg, mut)
39 | go func(wg *sync.WaitGroup, m *sync.RWMutex) {
40 | fmt.Println("Three R")
41 | mut.RLock()
42 | fmt.Println(score)
43 | mut.RUnlock()
44 | wg.Done()
45 | }(wg, mut)
46 |
47 | wg.Wait()
48 | fmt.Println(score)
49 | }
50 |
--------------------------------------------------------------------------------
/28channels/go.mod:
--------------------------------------------------------------------------------
1 | module channels
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/28channels/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "sync"
6 | )
7 |
8 | func main() {
9 | fmt.Println("Channels in golang- LearnCodeOnline.in")
10 |
11 | myCh := make(chan int, 2)
12 | wg := &sync.WaitGroup{}
13 |
14 | // fmt.Println(<-myCh)
15 | // myCh <- 5
16 | wg.Add(2)
17 | // R ONLY
18 | go func(ch <-chan int, wg *sync.WaitGroup) {
19 |
20 | val, isChanelOpen := <-myCh
21 |
22 | fmt.Println(isChanelOpen)
23 | fmt.Println(val)
24 |
25 | //fmt.Println(<-myCh)
26 |
27 | wg.Done()
28 | }(myCh, wg)
29 | // send ONLY
30 | go func(ch chan<- int, wg *sync.WaitGroup) {
31 | myCh <- 0
32 | close(myCh)
33 | // myCh <- 6
34 | wg.Done()
35 | }(myCh, wg)
36 |
37 | wg.Wait()
38 | }
39 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | # Golang series
2 |
3 | A complete guide to undersatnd golang programming language, web requests, JSON and creating web APIs with mongodb
4 |
5 | # [LearnCodeonline.in](https://pro.learncodeonline.in/learn)
6 |
7 | ## 01 Introduction to golang
8 |
9 | ## 02 Basics of golang
10 |
11 | ## 03 Memory management and datatypes in golang
12 |
13 | ## 04 Flow control in golang
14 |
15 | ## 05 Moving to web and modules
16 |
17 | ## 06 Building API in golang
18 |
19 | ## 07 Building API with mongoDB
20 |
21 | ## 08 Goroutines, mutex and channel
22 |
23 | > Future updates might come in this series but they will be uploaded only on LearnCodeonline.
24 |
25 | ## Will there be any support for questions in this series.
26 |
27 | Support for questions is available in all paid series only at LCO.
28 |
29 | ## There is a mistake in your code/explanation.
30 |
31 | It might be and I am sorry for that. Just send me updated version or explanation and I would love to add that below.
32 |
33 | ---
34 |
35 | ---
36 |
37 | ## Where can I reach you?
38 |
39 | You can reach me at [Instagram](https://www.instagram.com/hiteshchoudharyofficial/)
40 |
--------------------------------------------------------------------------------
/important.txt:
--------------------------------------------------------------------------------
1 | Hey there, Hitesh here...
2 |
3 | Thanks for watching the golang series.
4 |
5 | If you want to watch it in order and with community discussion use,
6 | https://courses.learnCodeOnline.in
7 |
8 | If you want to support me to create more such courses and indepth guide, you can
9 | support me by subscribing at https://pro.learnCodeOnline.in
10 |
11 | If you cannot afford that, that's fine too.
12 | A Hi on instagram would be cool too.
13 |
14 | Please don't hesitate to request another such topic.
15 | I would love to research it and make course on that.
16 |
17 |
18 | Catch you up in another video.
19 |
20 | Hitesh
--------------------------------------------------------------------------------
/lcowebserver/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | Part of exercise file for go lang course at
3 | https://web.learncodeonline.in
4 | */
5 |
6 | const express = require('express')
7 | const app = express()
8 | const port = 8000
9 |
10 | app.use(express.json());
11 | app.use(express.urlencoded({extended: true}));
12 |
13 | app.get('/', (req, res) => {
14 | res.status(200).send("Welcome to LearnCodeonline server")
15 | })
16 |
17 | app.get('/get', (req, res) => {
18 | res.status(200).json({message: "Hello from learnCodeonline.in"})
19 | })
20 |
21 |
22 | app.post('/post', (req, res) => {
23 | let myJson = req.body; // your JSON
24 |
25 | res.status(200).send(myJson);
26 | })
27 |
28 | app.post('/postform', (req, res) => {
29 | res.status(200).send(JSON.stringify(req.body));
30 | })
31 |
32 |
33 | app.listen(port, () => {
34 | console.log(`Example app listening at http://localhost:${port}`)
35 | })
--------------------------------------------------------------------------------
/lcowebserver/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lcowebserver",
3 | "version": "1.0.0",
4 | "description": "a web server for golang series",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "nodemon index.js"
8 | },
9 | "keywords": [
10 | "webserver",
11 | "lco"
12 | ],
13 | "author": "Hitesh Choudhary",
14 | "license": "ISC",
15 | "dependencies": {
16 | "express": "^4.17.1",
17 | "nodemon": "^2.0.12"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------