├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── chapter01
├── http-server-basic-authentication.go
├── http-server-basic-routing.go
├── http-server-gorilla-mux-routing.go
├── http-server-mux.go
├── http-server-request-logging.go
├── http-server.go
├── tcp-server-read-data.go
├── tcp-server-write-data.go
└── tcp-server.go
├── chapter02
├── first-template.go
├── form-validation.go
├── html-form-read.go
├── html-form-validation.go
├── html-form.go
├── serve-static-files-gorilla-mux.go
├── serve-static-files.go
├── static
│ └── css
│ │ └── main.css
├── templates
│ ├── first-template.html
│ ├── home.html
│ ├── login-form.html
│ └── upload-file.html
└── upload-file.go
├── chapter03
├── html-form-login-logout.go
├── http-caching.go
├── http-cookie.go
├── http-error-handling.go
├── http-session-redis.go
├── http-session.go
└── templates
│ ├── home.html
│ └── login-form.html
├── chapter04
├── connect-mongodb.go
├── connect-mysql.go
├── create-record-mongodb.go
├── create-record-mysql.go
├── delete-record-mongodb.go
├── delete-record-mysql.go
├── read-record-mongodb.go
├── read-record-mysql.go
├── update-record-mongodb.go
└── update-record-mysql.go
├── chapter05
├── angularjs-client
│ ├── assets
│ │ ├── index.html
│ │ └── main.js
│ └── server.go
├── http-rest-client.go
├── http-rest-delete.go
├── http-rest-get.go
├── http-rest-post.go
├── http-rest-put.go
├── http-rest-versioning.go
├── reactjs-client
│ ├── app
│ │ ├── components
│ │ │ ├── add-employee.jsx
│ │ │ ├── employee-app.jsx
│ │ │ ├── employee-list.jsx
│ │ │ └── employee.jsx
│ │ └── main.js
│ ├── assets
│ │ └── index.html
│ ├── package.json
│ ├── server.go
│ └── webpack.config.js
└── vuejs-client
│ ├── assets
│ ├── index.html
│ └── main.js
│ └── server.go
├── chapter06
├── api
│ └── greeting-api.go
├── proto
│ ├── hello.pb.go
│ └── hello.proto
└── services
│ ├── first-greeting-service.go
│ └── second-greeting-service.go
├── chapter07
├── index.html
├── websocket-server.go
└── websocket-server_test.go
├── chapter08
├── my-first-beego-project
│ ├── conf
│ │ └── app.conf
│ ├── controllers
│ │ ├── cachecontroller.go
│ │ ├── default.go
│ │ ├── errorcontroller.go
│ │ ├── firstcontroller.go
│ │ └── sessioncontroller.go
│ ├── filters
│ │ └── firstfilter.go
│ ├── main.go
│ ├── my-first-beego-project
│ ├── routers
│ │ └── router.go
│ ├── static
│ │ └── js
│ │ │ └── reload.min.js
│ ├── swagger
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── index.html
│ │ ├── oauth2-redirect.html
│ │ ├── swagger-ui-bundle.js
│ │ ├── swagger-ui-bundle.js.map
│ │ ├── swagger-ui-standalone-preset.js
│ │ ├── swagger-ui-standalone-preset.js.map
│ │ ├── swagger-ui.css
│ │ ├── swagger-ui.css.map
│ │ ├── swagger-ui.js
│ │ ├── swagger-ui.js.map
│ │ ├── swagger.json
│ │ └── swagger.yml
│ ├── tests
│ │ └── default_test.go
│ └── views
│ │ ├── 404.tpl
│ │ ├── 500.tpl
│ │ ├── dashboard.tpl
│ │ ├── genericerror.tpl
│ │ └── index.tpl
└── nginx.conf
├── chapter09
├── build-go-docker-image
│ ├── Dockerfile
│ └── http-server.go
└── build-go-webapp-docker-image
│ ├── Dockerfile
│ └── http-server.go
├── chapter10
├── .gitignore
├── certs
│ └── domain.csr
├── create-jwt.go
├── http-jwt.go
├── http-rest-api-secured.go
├── http-rest-api.go
├── https-server.go
├── prevent-csrf.go
└── sign-up.html
└── chapter11
├── .gitignore
└── copy-go-webapp-to-ec2
└── http-server.go
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Windows image file caches
2 | Thumbs.db
3 | ehthumbs.db
4 |
5 | # Folder config file
6 | Desktop.ini
7 |
8 | # Recycle Bin used on file shares
9 | $RECYCLE.BIN/
10 |
11 | # Windows Installer files
12 | *.cab
13 | *.msi
14 | *.msm
15 | *.msp
16 |
17 | # Windows shortcuts
18 | *.lnk
19 |
20 | # =========================
21 | # Operating System Files
22 | # =========================
23 |
24 | # OSX
25 | # =========================
26 |
27 | .DS_Store
28 | .AppleDouble
29 | .LSOverride
30 |
31 | # Thumbnails
32 | ._*
33 |
34 | # Files that might appear in the root of a volume
35 | .DocumentRevisions-V100
36 | .fseventsd
37 | .Spotlight-V100
38 | .TemporaryItems
39 | .Trashes
40 | .VolumeIcon.icns
41 |
42 | # Directories potentially created on remote AFP share
43 | .AppleDB
44 | .AppleDesktop
45 | Network Trash Folder
46 | Temporary Items
47 | .apdisk
48 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Packt
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # Go Web Development Cookbook
5 | This is the code repository for [Go Web Development Cookbook](https://www.packtpub.com/web-development/go-web-development-cookbook?utm_source=github&utm_medium=repository&utm_campaign=9781787286740), published by [Packt](https://www.packtpub.com/?utm_source=github). It contains all the supporting project files necessary to work through the book from start to finish.
6 | ## About the Book
7 | Go is an open source programming language that is designed to scale and support concurrency at the language level. This gives you the liberty to write large concurrent web applications with ease. From creating web application to deploying them on Amazon Cloud Services, this book will be your one-stop guide to learn web development in Go. The Go Web Development Cookbook teaches you how to create REST services, write microservices, and deploy Go Docker containers. Whether you are new to programming or a professional developer, this book will help get you up to speed with web development in Go. We will focus on writing modular code in Go; in-depth informative examples build the base, one step at a time. You will learn how to create a server, work with static files, SQL, NoSQL databases, and Beego. You will also learn how to create and secure REST services, and create and deploy Go web application and Go Docker containers on Amazon Cloud Services. By the end of the book, you will be able to apply the skills you've gained in Go to create and explore web applications in any domain.
8 | ## Instructions and Navigation
9 | All of the code is organized into folders. Each folder starts with a number followed by the application name. For example, Chapter02.
10 |
11 |
12 |
13 | The code will look like the following:
14 | ```
15 | for
16 | {
17 | conn, err := listener.Accept()
18 | if err != nil
19 | {
20 | log.Fatal("Error accepting: ", err.Error())
21 | }
22 | log.Println(conn)
23 | }
24 | ```
25 |
26 | Readers should possess basic knowledge of Go and have Go installed on the machine to execute the instructions and the code.
27 |
28 | ## Related Products
29 | * [Go Network Programming Cookbook](https://www.packtpub.com/application-development/go-network-programming-cookbook?utm_source=github&utm_medium=repository&utm_campaign=9781788392860)
30 |
31 | * [Mastering Go](https://www.packtpub.com/networking-and-servers/mastering-go?utm_source=github&utm_medium=repository&utm_campaign=9781788626545)
32 |
33 | * [Security with Go](https://www.packtpub.com/networking-and-servers/security-go?utm_source=github&utm_medium=repository&utm_campaign=9781788627917)
34 |
35 | ### Suggestions and Feedback
36 | [Click here](https://docs.google.com/forms/d/e/1FAIpQLSe5qwunkGf6PUvzPirPDtuy1Du5Rlzew23UBp2S-P3wB-GcwQ/viewform) if you have any feedback or suggestions.
37 | ### Download a free PDF
38 |
39 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost. Simply click on the link to claim your free PDF.
40 |
https://packt.link/free-ebook/9781787286740
--------------------------------------------------------------------------------
/chapter01/http-server-basic-authentication.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "crypto/subtle"
5 | "fmt"
6 | "log"
7 | "net/http"
8 | )
9 |
10 | const (
11 | CONN_HOST = "localhost"
12 | CONN_PORT = "8080"
13 | ADMIN_USER = "admin"
14 | ADMIN_PASSWORD = "admin"
15 | )
16 |
17 | func helloWorld(w http.ResponseWriter, r *http.Request) {
18 | fmt.Fprintf(w, "Hello World!")
19 | }
20 |
21 | func BasicAuth(handler http.HandlerFunc, realm string) http.HandlerFunc {
22 |
23 | return func(w http.ResponseWriter, r *http.Request) {
24 |
25 | user, pass, ok := r.BasicAuth()
26 |
27 | if !ok || subtle.ConstantTimeCompare([]byte(user), []byte(ADMIN_USER)) != 1 || subtle.ConstantTimeCompare([]byte(pass), []byte(ADMIN_PASSWORD)) != 1 {
28 | w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`)
29 | w.WriteHeader(401)
30 | w.Write([]byte("You are Unauthorized to access the application.\n"))
31 | return
32 | }
33 |
34 | handler(w, r)
35 | }
36 | }
37 |
38 | func main() {
39 | http.HandleFunc("/", BasicAuth(helloWorld, "Please enter your username and password"))
40 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
41 | if err != nil {
42 | log.Fatal("error starting http server : ", err)
43 | return
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/chapter01/http-server-basic-routing.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 | )
8 |
9 | const (
10 | CONN_HOST = "localhost"
11 | CONN_PORT = "8080"
12 | )
13 |
14 | func helloWorld(w http.ResponseWriter, r *http.Request) {
15 | fmt.Fprintf(w, "Hello World!")
16 | }
17 |
18 | func login(w http.ResponseWriter, r *http.Request) {
19 | fmt.Fprintf(w, "Login Page!")
20 | }
21 |
22 | func logout(w http.ResponseWriter, r *http.Request) {
23 | fmt.Fprintf(w, "Logout Page!")
24 | }
25 |
26 | func main() {
27 | http.HandleFunc("/", helloWorld)
28 | http.HandleFunc("/login", login)
29 | http.HandleFunc("/logout", logout)
30 |
31 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
32 | if err != nil {
33 | log.Fatal("error starting http server : ", err)
34 | return
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/chapter01/http-server-gorilla-mux-routing.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/gorilla/mux"
7 | )
8 |
9 | const (
10 | CONN_HOST = "localhost"
11 | CONN_PORT = "8080"
12 | )
13 |
14 | var GetRequestHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
15 | w.Write([]byte("Hello World!"))
16 | })
17 |
18 | var PostRequestHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
19 | w.Write([]byte("It's a Post Request!"))
20 | })
21 |
22 | var PathVariableHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
23 | vars := mux.Vars(r)
24 | name := vars["name"]
25 | w.Write([]byte("Hi " + name))
26 | })
27 |
28 | func main() {
29 | router := mux.NewRouter()
30 | router.Handle("/", GetRequestHandler).Methods("GET")
31 | router.Handle("/post", PostRequestHandler).Methods("POST")
32 | router.Handle("/hello/{name}", PathVariableHandler).Methods("GET", "PUT")
33 | http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
34 | }
35 |
--------------------------------------------------------------------------------
/chapter01/http-server-mux.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "io"
5 | "log"
6 | "net/http"
7 |
8 | "github.com/gorilla/handlers"
9 | )
10 |
11 | const (
12 | CONN_HOST = "localhost"
13 | CONN_PORT = "8080"
14 | )
15 |
16 | func helloWorld(w http.ResponseWriter, r *http.Request) {
17 | io.WriteString(w, "Hello World!")
18 | }
19 |
20 | func main() {
21 | mux := http.NewServeMux()
22 | mux.HandleFunc("/", helloWorld)
23 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, handlers.CompressHandler(mux))
24 | if err != nil {
25 | log.Fatal("error starting http server : ", err)
26 | return
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/chapter01/http-server-request-logging.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "net/http"
6 | "os"
7 |
8 | "github.com/gorilla/handlers"
9 | "github.com/gorilla/mux"
10 | )
11 |
12 | const (
13 | CONN_HOST = "localhost"
14 | CONN_PORT = "8080"
15 | )
16 |
17 | var GetRequestHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
18 | w.Write([]byte("Hello World!"))
19 | })
20 |
21 | var PostRequestHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
22 | w.Write([]byte("It's a Post Request!"))
23 | })
24 |
25 | var PathVariableHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
26 | vars := mux.Vars(r)
27 | name := vars["name"]
28 | w.Write([]byte("Hi " + name))
29 | })
30 |
31 | func main() {
32 | router := mux.NewRouter()
33 | router.Handle("/", handlers.LoggingHandler(os.Stdout, http.HandlerFunc(GetRequestHandler))).Methods("GET")
34 |
35 | logFile, err := os.OpenFile("server.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
36 | if err != nil {
37 | log.Fatal("error starting http server : ", err)
38 | return
39 | }
40 | router.Handle("/post", handlers.LoggingHandler(logFile, PostRequestHandler)).Methods("POST")
41 | router.Handle("/hello/{name}", handlers.CombinedLoggingHandler(logFile, PathVariableHandler)).Methods("GET")
42 | http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
43 | }
44 |
--------------------------------------------------------------------------------
/chapter01/http-server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 | )
8 |
9 | const (
10 | CONN_HOST = "localhost"
11 | CONN_PORT = "8080"
12 | )
13 |
14 | func helloWorld(w http.ResponseWriter, r *http.Request) {
15 | fmt.Fprintf(w, "Hello World!")
16 | }
17 |
18 | func main() {
19 | http.HandleFunc("/", helloWorld)
20 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
21 | if err != nil {
22 | log.Fatal("error starting http server : ", err)
23 | return
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/chapter01/tcp-server-read-data.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "log"
7 | "net"
8 | )
9 |
10 | const (
11 | CONN_HOST = "localhost"
12 | CONN_PORT = "8080"
13 | CONN_TYPE = "tcp"
14 | )
15 |
16 | func main() {
17 | listener, err := net.Listen(CONN_TYPE, CONN_HOST+":"+CONN_PORT)
18 | if err != nil {
19 | log.Fatal("Error starting tcp server : ", err)
20 | }
21 | defer listener.Close()
22 | log.Println("Listening on " + CONN_HOST + ":" + CONN_PORT)
23 |
24 | for {
25 | conn, err := listener.Accept()
26 | if err != nil {
27 | log.Fatal("Error accepting: ", err.Error())
28 | }
29 | go handleRequest(conn)
30 | }
31 | }
32 |
33 | func handleRequest(conn net.Conn) {
34 | message, err := bufio.NewReader(conn).ReadString('\n')
35 |
36 | if err != nil {
37 | fmt.Println("Error reading:", err.Error())
38 | }
39 | fmt.Print("Message Received from the client: ", string(message))
40 | conn.Close()
41 | }
42 |
--------------------------------------------------------------------------------
/chapter01/tcp-server-write-data.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "log"
7 | "net"
8 | )
9 |
10 | const (
11 | CONN_HOST = "localhost"
12 | CONN_PORT = "8080"
13 | CONN_TYPE = "tcp"
14 | )
15 |
16 | func main() {
17 | listener, err := net.Listen(CONN_TYPE, CONN_HOST+":"+CONN_PORT)
18 | if err != nil {
19 | log.Fatal("Error starting tcp server : ", err)
20 | }
21 | defer listener.Close()
22 | log.Println("Listening on " + CONN_HOST + ":" + CONN_PORT)
23 |
24 | for {
25 | conn, err := listener.Accept()
26 | if err != nil {
27 | log.Fatal("Error accepting: ", err.Error())
28 | }
29 | go handleRequest(conn)
30 | }
31 | }
32 |
33 | func handleRequest(conn net.Conn) {
34 | message, err := bufio.NewReader(conn).ReadString('\n')
35 |
36 | if err != nil {
37 | fmt.Println("Error reading: ", err.Error())
38 | }
39 | conn.Write([]byte(message + "\n"))
40 | fmt.Print("Message Received:", string(message))
41 | conn.Close()
42 | }
43 |
--------------------------------------------------------------------------------
/chapter01/tcp-server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "net"
6 | )
7 |
8 | const (
9 | CONN_HOST = "localhost"
10 | CONN_PORT = "8080"
11 | CONN_TYPE = "tcp"
12 | )
13 |
14 | func main() {
15 | listener, err := net.Listen(CONN_TYPE, CONN_HOST+":"+CONN_PORT)
16 | if err != nil {
17 | log.Fatal("Error starting tcp server : ", err)
18 | }
19 |
20 | defer listener.Close()
21 | log.Println("Listening on " + CONN_HOST + ":" + CONN_PORT)
22 |
23 | for {
24 | conn, err := listener.Accept()
25 | if err != nil {
26 | log.Fatal("Error accepting: ", err.Error())
27 | }
28 | log.Println(conn)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/chapter02/first-template.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "html/template"
5 | "log"
6 | "net/http"
7 | )
8 |
9 | const (
10 | CONN_HOST = "localhost"
11 | CONN_PORT = "8080"
12 | )
13 |
14 | type Person struct {
15 | Id string
16 | Name string
17 | }
18 |
19 | func renderTemplate(w http.ResponseWriter, r *http.Request) {
20 | person := Person{Id: "1", Name: "Foo"}
21 | parsedTemplate, _ := template.ParseFiles("templates/first-template.html")
22 | err := parsedTemplate.Execute(w, person)
23 | if err != nil {
24 | log.Printf("Error occurred while executing the template or writing its output : ", err)
25 | return
26 | }
27 | }
28 |
29 | func main() {
30 | http.HandleFunc("/", renderTemplate)
31 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
32 | if err != nil {
33 | log.Fatal("error starting http server : ", err)
34 | return
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/chapter02/form-validation.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "github.com/asaskevich/govalidator"
4 |
5 | const (
6 | CONN_HOST = "localhost"
7 | CONN_PORT = "8080"
8 | )
9 |
10 | type User struct {
11 | Username string `valid:"alpha,required"`
12 | Password string `valid:"alpha,required"`
13 | }
14 |
15 | func main() {
16 | user := User{Username: "something", Password: ""}
17 | valid, err := govalidator.ValidateStruct(user)
18 |
19 | if !valid {
20 | usernameError := govalidator.ErrorByField(err, "Username")
21 | passwordError := govalidator.ErrorByField(err, "Password")
22 | if usernameError != "" {
23 | println("Username Error :: " + usernameError)
24 | }
25 | if passwordError != "" {
26 | println("Password Error :: " + passwordError)
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/chapter02/html-form-read.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "html/template"
6 | "log"
7 | "net/http"
8 |
9 | "github.com/gorilla/schema"
10 | )
11 |
12 | const (
13 | CONN_HOST = "localhost"
14 | CONN_PORT = "8080"
15 | )
16 |
17 | type User struct {
18 | Username string
19 | Password string
20 | }
21 |
22 | func readForm(r *http.Request) *User {
23 | r.ParseForm()
24 | user := new(User)
25 | decoder := schema.NewDecoder()
26 | decodeErr := decoder.Decode(user, r.PostForm)
27 | if decodeErr != nil {
28 | log.Printf("error mapping parsed form data to struct : ", decodeErr)
29 | }
30 | return user
31 | }
32 |
33 | func login(w http.ResponseWriter, r *http.Request) {
34 | if r.Method == "GET" {
35 | parsedTemplate, _ := template.ParseFiles("templates/login-form.html")
36 | parsedTemplate.Execute(w, nil)
37 | } else {
38 | user := readForm(r)
39 | fmt.Fprintf(w, "Hello "+user.Username+"!")
40 | }
41 | }
42 |
43 | func main() {
44 | http.HandleFunc("/", login)
45 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
46 | if err != nil {
47 | log.Fatal("error starting http server : ", err)
48 | return
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/chapter02/html-form-validation.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "html/template"
6 | "log"
7 | "net/http"
8 |
9 | "github.com/asaskevich/govalidator"
10 | "github.com/gorilla/schema"
11 | )
12 |
13 | const (
14 | CONN_HOST = "localhost"
15 | CONN_PORT = "8080"
16 | USERNAME_ERROR_MESSAGE = "Please enter a valid Username"
17 | PASSWORD_ERROR_MESSAGE = "Please enter a valid Password"
18 | GENERIC_ERROR_MESSAGE = "Validation Error"
19 | )
20 |
21 | type User struct {
22 | Username string `valid:"alpha,required"`
23 | Password string `valid:"alpha,required"`
24 | }
25 |
26 | func readForm(r *http.Request) *User {
27 | r.ParseForm()
28 | user := new(User)
29 | decoder := schema.NewDecoder()
30 | decodeErr := decoder.Decode(user, r.PostForm)
31 | if decodeErr != nil {
32 | log.Printf("error mapping parsed form data to struct : ", decodeErr)
33 | }
34 | return user
35 | }
36 |
37 | func validateUser(w http.ResponseWriter, r *http.Request, user *User) (bool, string) {
38 | valid, validationError := govalidator.ValidateStruct(user)
39 |
40 | if !valid {
41 | usernameError := govalidator.ErrorByField(validationError, "Username")
42 | passwordError := govalidator.ErrorByField(validationError, "Password")
43 | if usernameError != "" {
44 | log.Printf("username validation error : ", usernameError)
45 | return valid, USERNAME_ERROR_MESSAGE
46 | }
47 | if passwordError != "" {
48 | log.Printf("password validation error : ", passwordError)
49 | return valid, PASSWORD_ERROR_MESSAGE
50 | }
51 | }
52 | return valid, GENERIC_ERROR_MESSAGE
53 | }
54 |
55 | func login(w http.ResponseWriter, r *http.Request) {
56 | if r.Method == "GET" {
57 | parsedTemplate, _ := template.ParseFiles("templates/login-form.html")
58 | parsedTemplate.Execute(w, nil)
59 | } else {
60 | user := readForm(r)
61 | valid, validationErrorMessage := validateUser(w, r, user)
62 | if !valid {
63 | fmt.Fprintf(w, validationErrorMessage)
64 | return
65 | }
66 | fmt.Fprintf(w, "Hello "+user.Username+"!")
67 | }
68 | }
69 |
70 | func main() {
71 | http.HandleFunc("/", login)
72 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
73 | if err != nil {
74 | log.Fatal("error starting http server : ", err)
75 | return
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/chapter02/html-form.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "html/template"
5 | "log"
6 | "net/http"
7 | )
8 |
9 | const (
10 | CONN_HOST = "localhost"
11 | CONN_PORT = "8080"
12 | )
13 |
14 | func login(w http.ResponseWriter, r *http.Request) {
15 | parsedTemplate, _ := template.ParseFiles("templates/login-form.html")
16 | parsedTemplate.Execute(w, nil)
17 | }
18 |
19 | func main() {
20 | http.HandleFunc("/", login)
21 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
22 | if err != nil {
23 | log.Fatal("error starting http server : ", err)
24 | return
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter02/serve-static-files-gorilla-mux.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "html/template"
5 | "log"
6 | "net/http"
7 |
8 | "github.com/gorilla/mux"
9 | )
10 |
11 | const (
12 | CONN_HOST = "localhost"
13 | CONN_PORT = "8080"
14 | )
15 |
16 | type Person struct {
17 | Id string
18 | Name string
19 | }
20 |
21 | func renderTemplate(w http.ResponseWriter, r *http.Request) {
22 | person := Person{Id: "1", Name: "Foo"}
23 | parsedTemplate, _ := template.ParseFiles("templates/first-template.html")
24 | err := parsedTemplate.Execute(w, person)
25 | if err != nil {
26 | log.Printf("Error occurred while executing the template or writing its output : ", err)
27 | return
28 | }
29 | }
30 |
31 | func main() {
32 | router := mux.NewRouter()
33 | router.HandleFunc("/", renderTemplate).Methods("GET")
34 | router.PathPrefix("/").Handler(http.StripPrefix("/static", http.FileServer(http.Dir("static/"))))
35 |
36 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
37 | if err != nil {
38 | log.Fatal("error starting http server : ", err)
39 | return
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/chapter02/serve-static-files.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "html/template"
5 | "log"
6 | "net/http"
7 | )
8 |
9 | const (
10 | CONN_HOST = "localhost"
11 | CONN_PORT = "8080"
12 | )
13 |
14 | type Person struct {
15 | Id string
16 | Name string
17 | }
18 |
19 | func renderTemplate(w http.ResponseWriter, r *http.Request) {
20 | person := Person{Id: "1", Name: "Foo"}
21 | parsedTemplate, _ := template.ParseFiles("templates/first-template.html")
22 | err := parsedTemplate.Execute(w, person)
23 | if err != nil {
24 | log.Printf("Error occurred while executing the template or writing its output : ", err)
25 | return
26 | }
27 | }
28 |
29 | func main() {
30 | fileServer := http.FileServer(http.Dir("static"))
31 | http.Handle("/static/", http.StripPrefix("/static/", fileServer))
32 | http.HandleFunc("/", renderTemplate)
33 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
34 | if err != nil {
35 | log.Fatal("error starting http server : ", err)
36 | return
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/chapter02/static/css/main.css:
--------------------------------------------------------------------------------
1 | body {color: #00008B}
2 |
--------------------------------------------------------------------------------
/chapter02/templates/first-template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | First Template
5 |
6 |
7 |
8 | Hello {{.Name}}!
9 | Your Id is {{.Id}}
10 |
11 |
12 |
--------------------------------------------------------------------------------
/chapter02/templates/home.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Welcome {{.userName}}!
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/chapter02/templates/login-form.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | First Form
4 |
5 |
6 | Login
7 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/chapter02/templates/upload-file.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | File Upload
5 |
6 |
7 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/chapter02/upload-file.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "html/template"
6 | "io"
7 | "log"
8 | "net/http"
9 | "os"
10 | )
11 |
12 | const (
13 | CONN_HOST = "localhost"
14 | CONN_PORT = "8080"
15 | )
16 |
17 | func fileHandler(w http.ResponseWriter, r *http.Request) {
18 | file, header, err := r.FormFile("file")
19 | if err != nil {
20 | log.Printf("error getting a file for the provided form key : ", err)
21 | return
22 | }
23 |
24 | defer file.Close()
25 |
26 | out, pathError := os.Create("/tmp/uploadedFile")
27 | if pathError != nil {
28 | log.Printf("error creating a file for writing : ", pathError)
29 | return
30 | }
31 | defer out.Close()
32 |
33 | _, copyFileError := io.Copy(out, file)
34 |
35 | if copyFileError != nil {
36 | log.Printf("error occurred while file copy : ", copyFileError)
37 | }
38 |
39 | fmt.Fprintf(w, "File uploaded successfully : "+header.Filename)
40 | }
41 |
42 | func index(w http.ResponseWriter, r *http.Request) {
43 | parsedTemplate, _ := template.ParseFiles("templates/upload-file.html")
44 | parsedTemplate.Execute(w, nil)
45 | }
46 |
47 | func main() {
48 | http.HandleFunc("/", index)
49 | http.HandleFunc("/upload", fileHandler)
50 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
51 | if err != nil {
52 | log.Fatal("error starting http server : ", err)
53 | return
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/chapter03/html-form-login-logout.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "html/template"
5 | "log"
6 | "net/http"
7 |
8 | "github.com/gorilla/mux"
9 | "github.com/gorilla/securecookie"
10 | )
11 |
12 | const (
13 | CONN_HOST = "localhost"
14 | CONN_PORT = "8080"
15 | )
16 |
17 | var cookieHandler = securecookie.New(
18 | securecookie.GenerateRandomKey(64),
19 | securecookie.GenerateRandomKey(32))
20 |
21 | func getUserName(request *http.Request) (userName string) {
22 | cookie, err := request.Cookie("session")
23 |
24 | if err == nil {
25 | cookieValue := make(map[string]string)
26 | err = cookieHandler.Decode("session", cookie.Value, &cookieValue)
27 | if err == nil {
28 | userName = cookieValue["username"]
29 | }
30 | }
31 | return userName
32 | }
33 |
34 | func setSession(userName string, response http.ResponseWriter) {
35 | value := map[string]string{
36 | "username": userName,
37 | }
38 | encoded, err := cookieHandler.Encode("session", value)
39 |
40 | if err == nil {
41 | cookie := &http.Cookie{
42 | Name: "session",
43 | Value: encoded,
44 | Path: "/",
45 | }
46 | http.SetCookie(response, cookie)
47 | }
48 | }
49 |
50 | func clearSession(response http.ResponseWriter) {
51 | cookie := &http.Cookie{
52 | Name: "session",
53 | Value: "",
54 | Path: "/",
55 | MaxAge: -1,
56 | }
57 | http.SetCookie(response, cookie)
58 | }
59 |
60 | func login(response http.ResponseWriter, request *http.Request) {
61 | username := request.FormValue("username")
62 | password := request.FormValue("password")
63 | target := "/"
64 | if username != "" && password != "" {
65 | setSession(username, response)
66 | target = "/home"
67 | }
68 | http.Redirect(response, request, target, 302)
69 | }
70 |
71 | func logout(response http.ResponseWriter, request *http.Request) {
72 | clearSession(response)
73 | http.Redirect(response, request, "/", 302)
74 | }
75 |
76 | func loginPage(w http.ResponseWriter, r *http.Request) {
77 | parsedTemplate, _ := template.ParseFiles("templates/login-form.html")
78 | parsedTemplate.Execute(w, nil)
79 | }
80 |
81 | func homePage(response http.ResponseWriter, request *http.Request) {
82 | userName := getUserName(request)
83 | if userName != "" {
84 | data := map[string]interface{}{
85 | "userName": userName,
86 | }
87 | parsedTemplate, _ := template.ParseFiles("templates/home.html")
88 | parsedTemplate.Execute(response, data)
89 | } else {
90 | http.Redirect(response, request, "/", 302)
91 | }
92 | }
93 |
94 | func main() {
95 | var router = mux.NewRouter()
96 | router.HandleFunc("/", loginPage)
97 | router.HandleFunc("/home", homePage)
98 |
99 | router.HandleFunc("/login", login).Methods("POST")
100 | router.HandleFunc("/logout", logout).Methods("POST")
101 |
102 | http.Handle("/", router)
103 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
104 | if err != nil {
105 | log.Fatal("error starting http server : ", err)
106 | return
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/chapter03/http-caching.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 | "time"
8 |
9 | "github.com/patrickmn/go-cache"
10 | )
11 |
12 | const (
13 | CONN_HOST = "localhost"
14 | CONN_PORT = "8080"
15 | )
16 |
17 | var newCache *cache.Cache
18 |
19 | func init() {
20 | newCache = cache.New(5*time.Minute, 10*time.Minute)
21 | newCache.Set("foo", "bar", cache.DefaultExpiration)
22 | }
23 |
24 | func getFromCache(w http.ResponseWriter, r *http.Request) {
25 | foo, found := newCache.Get("foo")
26 | if found {
27 | log.Print("Key Found in Cache with value as :: ", foo.(string))
28 | fmt.Fprintf(w, "Hello "+foo.(string))
29 | } else {
30 | log.Print("Key Not Found in Cache :: ", "foo")
31 | fmt.Fprintf(w, "Key Not Found in Cache")
32 | }
33 | }
34 |
35 | func main() {
36 | http.HandleFunc("/", getFromCache)
37 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
38 | if err != nil {
39 | log.Fatal("error starting http server : ", err)
40 | return
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/chapter03/http-cookie.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 |
8 | "github.com/gorilla/securecookie"
9 | )
10 |
11 | const (
12 | CONN_HOST = "localhost"
13 | CONN_PORT = "8080"
14 | )
15 |
16 | var cookieHandler *securecookie.SecureCookie
17 |
18 | func init() {
19 | cookieHandler = securecookie.New(securecookie.GenerateRandomKey(64), securecookie.GenerateRandomKey(32))
20 | }
21 |
22 | func createCookie(w http.ResponseWriter, r *http.Request) {
23 | value := map[string]string{
24 | "username": "Foo",
25 | }
26 | base64Encoded, err := cookieHandler.Encode("key", value)
27 | if err == nil {
28 | cookie := &http.Cookie{
29 | Name: "first-cookie",
30 | Value: base64Encoded,
31 | Path: "/",
32 | }
33 | http.SetCookie(w, cookie)
34 | }
35 | w.Write([]byte(fmt.Sprintf("Cookie created.")))
36 | }
37 |
38 | func readCookie(w http.ResponseWriter, r *http.Request) {
39 | log.Printf("Reading Cookie..")
40 | cookie, err := r.Cookie("first-cookie")
41 | if cookie != nil && err == nil {
42 | value := make(map[string]string)
43 | if err = cookieHandler.Decode("key", cookie.Value, &value); err == nil {
44 | w.Write([]byte(fmt.Sprintf("Hello %v \n", value["username"])))
45 | }
46 | } else {
47 | log.Printf("Cookie not found..")
48 | w.Write([]byte(fmt.Sprint("Hello")))
49 | }
50 | }
51 |
52 | func main() {
53 | http.HandleFunc("/create", createCookie)
54 | http.HandleFunc("/read", readCookie)
55 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
56 | if err != nil {
57 | log.Fatal("error starting http server : ", err)
58 | return
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/chapter03/http-error-handling.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "log"
7 | "net/http"
8 | "strings"
9 |
10 | "github.com/gorilla/mux"
11 | )
12 |
13 | const (
14 | CONN_HOST = "localhost"
15 | CONN_PORT = "8080"
16 | )
17 |
18 | type NameNotFoundError struct {
19 | Code int
20 | Err error
21 | }
22 |
23 | func (nameNotFoundError NameNotFoundError) Error() string {
24 | return nameNotFoundError.Err.Error()
25 | }
26 |
27 | type WrapperHandler func(http.ResponseWriter, *http.Request) error
28 |
29 | func (wrapperHandler WrapperHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
30 | err := wrapperHandler(w, r)
31 | if err != nil {
32 | switch e := err.(type) {
33 | case NameNotFoundError:
34 | log.Printf("HTTP %s - %d", e.Err, e.Code)
35 | http.Error(w, e.Err.Error(), e.Code)
36 | default:
37 | http.Error(w, http.StatusText(http.StatusInternalServerError),
38 | http.StatusInternalServerError)
39 | }
40 | }
41 | }
42 |
43 | func getName(w http.ResponseWriter, r *http.Request) error {
44 | vars := mux.Vars(r)
45 | name := vars["name"]
46 | if strings.EqualFold(name, "foo") {
47 | fmt.Fprintf(w, "Hello "+name)
48 | return nil
49 | } else {
50 | return NameNotFoundError{500, errors.New("Name Not Found")}
51 | }
52 | }
53 |
54 | func main() {
55 | router := mux.NewRouter()
56 | router.Handle("/employee/get/{name}", WrapperHandler(getName)).Methods("GET")
57 |
58 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
59 | if err != nil {
60 | log.Fatal("error starting http server : ", err)
61 | return
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/chapter03/http-session-redis.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 |
8 | "github.com/gorilla/sessions"
9 |
10 | redisStore "gopkg.in/boj/redistore.v1"
11 | )
12 |
13 | const (
14 | CONN_HOST = "localhost"
15 | CONN_PORT = "8080"
16 | )
17 |
18 | var store *redisStore.RediStore
19 | var err error
20 |
21 | func init() {
22 | store, err = redisStore.NewRediStore(10, "tcp", ":6379", "", []byte("secret-key"))
23 | if err != nil {
24 | log.Fatal("error getting redis store : ", err)
25 | }
26 | }
27 |
28 | func home(w http.ResponseWriter, r *http.Request) {
29 | session, _ := store.Get(r, "session-name")
30 | var authenticated interface{} = session.Values["authenticated"]
31 | if authenticated != nil {
32 | isAuthenticated := session.Values["authenticated"].(bool)
33 | if !isAuthenticated {
34 | http.Error(w, "You are unauthorized to view the page", http.StatusForbidden)
35 | return
36 | }
37 | fmt.Fprintln(w, "Home Page")
38 | } else {
39 | http.Error(w, "You are unauthorized to view the page", http.StatusForbidden)
40 | return
41 | }
42 | }
43 |
44 | func login(w http.ResponseWriter, r *http.Request) {
45 | session, _ := store.Get(r, "session-name")
46 | session.Values["authenticated"] = true
47 | if err = sessions.Save(r, w); err != nil {
48 | log.Fatalf("Error saving session: %v", err)
49 | }
50 | fmt.Fprintln(w, "You have successfully logged in.")
51 | }
52 |
53 | func logout(w http.ResponseWriter, r *http.Request) {
54 | session, _ := store.Get(r, "session-name")
55 | session.Values["authenticated"] = false
56 | session.Save(r, w)
57 | fmt.Fprintln(w, "You have successfully logged out.")
58 | }
59 |
60 | func main() {
61 | http.HandleFunc("/home", home)
62 | http.HandleFunc("/login", login)
63 | http.HandleFunc("/logout", logout)
64 |
65 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
66 | defer store.Close()
67 | if err != nil {
68 | log.Fatal("error starting http server : ", err)
69 | return
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/chapter03/http-session.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 |
8 | "github.com/gorilla/sessions"
9 | )
10 |
11 | const (
12 | CONN_HOST = "localhost"
13 | CONN_PORT = "8080"
14 | )
15 |
16 | var store *sessions.CookieStore
17 |
18 | func init() {
19 | store = sessions.NewCookieStore([]byte("secret-key"))
20 | }
21 |
22 | func home(w http.ResponseWriter, r *http.Request) {
23 | session, _ := store.Get(r, "session-name")
24 | var authenticated interface{} = session.Values["authenticated"]
25 | if authenticated != nil {
26 | isAuthenticated := session.Values["authenticated"].(bool)
27 | if !isAuthenticated {
28 | http.Error(w, "You are unauthorized to view the page", http.StatusForbidden)
29 | return
30 | }
31 | fmt.Fprintln(w, "Home Page")
32 | } else {
33 | http.Error(w, "You are unauthorized to view the page", http.StatusForbidden)
34 | return
35 | }
36 | }
37 |
38 | func login(w http.ResponseWriter, r *http.Request) {
39 | session, _ := store.Get(r, "session-name")
40 | session.Values["authenticated"] = true
41 | session.Save(r, w)
42 | fmt.Fprintln(w, "You have successfully logged in.")
43 | }
44 |
45 | func logout(w http.ResponseWriter, r *http.Request) {
46 | session, _ := store.Get(r, "session-name")
47 | session.Values["authenticated"] = false
48 | session.Save(r, w)
49 | fmt.Fprintln(w, "You have successfully logged out.")
50 | }
51 |
52 | func main() {
53 | http.HandleFunc("/home", home)
54 | http.HandleFunc("/login", login)
55 | http.HandleFunc("/logout", logout)
56 |
57 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
58 | if err != nil {
59 | log.Fatal("error starting http server : ", err)
60 | return
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/chapter03/templates/home.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Welcome {{.userName}}!
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/chapter03/templates/login-form.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | First Form
4 |
5 |
6 | Login
7 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/chapter04/connect-mongodb.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 | "strings"
8 |
9 | mgo "gopkg.in/mgo.v2"
10 | )
11 |
12 | const (
13 | CONN_HOST = "localhost"
14 | CONN_PORT = "8080"
15 | MONGO_DB_URL = "127.0.0.1"
16 | )
17 |
18 | var session *mgo.Session
19 | var connectionError error
20 |
21 | func init() {
22 | session, connectionError = mgo.Dial(MONGO_DB_URL)
23 | if connectionError != nil {
24 | log.Fatal("error connecting to database :: ", connectionError)
25 | }
26 | session.SetMode(mgo.Monotonic, true)
27 | }
28 |
29 | func getDbNames(w http.ResponseWriter, r *http.Request) {
30 | db, err := session.DatabaseNames()
31 | if err != nil {
32 | log.Print("error getting database names :: ", err)
33 | return
34 | }
35 | fmt.Fprintf(w, "Databases names are :: %s", strings.Join(db, ", "))
36 | }
37 |
38 | func main() {
39 | http.HandleFunc("/", getDbNames)
40 | defer session.Close()
41 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
42 | if err != nil {
43 | log.Fatal("error starting http server :: ", err)
44 | return
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/chapter04/connect-mysql.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "log"
7 | "net/http"
8 |
9 | _ "github.com/go-sql-driver/mysql"
10 | )
11 |
12 | const (
13 | CONN_HOST = "localhost"
14 | CONN_PORT = "8080"
15 | DRIVER_NAME = "mysql"
16 | DATA_SOURCE_NAME = "root:password@/mydb"
17 | )
18 |
19 | var db *sql.DB
20 | var connectionError error
21 |
22 | func init() {
23 | db, connectionError = sql.Open(DRIVER_NAME, DATA_SOURCE_NAME)
24 | if connectionError != nil {
25 | log.Fatal("error connecting to database :: ", connectionError)
26 | }
27 | }
28 |
29 | func getCurrentDb(w http.ResponseWriter, r *http.Request) {
30 | rows, err := db.Query("SELECT DATABASE() as db")
31 | if err != nil {
32 | log.Print("error executing query :: ", err)
33 | return
34 | }
35 | var db string
36 | for rows.Next() {
37 | rows.Scan(&db)
38 | }
39 | fmt.Fprintf(w, "Current Database is :: %s", db)
40 | }
41 |
42 | func main() {
43 | http.HandleFunc("/", getCurrentDb)
44 | defer db.Close()
45 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
46 | if err != nil {
47 | log.Fatal("error starting http server :: ", err)
48 | return
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/chapter04/create-record-mongodb.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 | "strconv"
8 |
9 | "github.com/gorilla/mux"
10 |
11 | mgo "gopkg.in/mgo.v2"
12 | )
13 |
14 | const (
15 | CONN_HOST = "localhost"
16 | CONN_PORT = "8080"
17 | MONGO_DB_URL = "127.0.0.1"
18 | )
19 |
20 | var session *mgo.Session
21 | var connectionError error
22 |
23 | type Employee struct {
24 | Id int `json:"uid"`
25 | Name string `json:"name"`
26 | }
27 |
28 | func init() {
29 | session, connectionError = mgo.Dial(MONGO_DB_URL)
30 | if connectionError != nil {
31 | log.Fatal("error connecting to database :: ", connectionError)
32 | }
33 | session.SetMode(mgo.Monotonic, true)
34 | }
35 |
36 | func createDocument(w http.ResponseWriter, r *http.Request) {
37 | vals := r.URL.Query()
38 | name, nameOk := vals["name"]
39 | id, idOk := vals["id"]
40 | if nameOk && idOk {
41 | employeeId, err := strconv.Atoi(id[0])
42 | if err != nil {
43 | log.Print("error converting string id to int :: ", err)
44 | return
45 | }
46 | log.Print("going to insert document in database for name :: ", name[0])
47 | collection := session.DB("mydb").C("employee")
48 | err = collection.Insert(&Employee{employeeId, name[0]})
49 | if err != nil {
50 | log.Print("error occurred while inserting document in database :: ", err)
51 | return
52 | }
53 | fmt.Fprintf(w, "Last created document id is :: %s", id[0])
54 | } else {
55 | fmt.Fprintf(w, "Error occurred while creating document in database for name :: %s", name[0])
56 | }
57 | }
58 |
59 | func main() {
60 | router := mux.NewRouter()
61 | router.HandleFunc("/employee/create", createDocument).Methods("POST")
62 | defer session.Close()
63 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
64 | if err != nil {
65 | log.Fatal("error starting http server :: ", err)
66 | return
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/chapter04/create-record-mysql.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "log"
7 | "net/http"
8 | "strconv"
9 |
10 | _ "github.com/go-sql-driver/mysql"
11 | "github.com/gorilla/mux"
12 | )
13 |
14 | const (
15 | CONN_HOST = "localhost"
16 | CONN_PORT = "8080"
17 | DRIVER_NAME = "mysql"
18 | DATA_SOURCE_NAME = "root:password@/mydb"
19 | )
20 |
21 | var db *sql.DB
22 | var connectionError error
23 |
24 | func init() {
25 | db, connectionError = sql.Open(DRIVER_NAME, DATA_SOURCE_NAME)
26 | if connectionError != nil {
27 | log.Fatal("error connecting to database : ", connectionError)
28 | }
29 | }
30 |
31 | func createRecord(w http.ResponseWriter, r *http.Request) {
32 | vals := r.URL.Query()
33 | name, ok := vals["name"]
34 | if ok {
35 | log.Print("going to insert record in database for name : ", name[0])
36 | stmt, err := db.Prepare("INSERT employee SET name=?")
37 | if err != nil {
38 | log.Print("error preparing query :: ", err)
39 | return
40 | }
41 | result, err := stmt.Exec(name[0])
42 | if err != nil {
43 | log.Print("error executing query :: ", err)
44 | return
45 | }
46 | id, err := result.LastInsertId()
47 | fmt.Fprintf(w, "Last Inserted Record Id is :: %s", strconv.FormatInt(id, 10))
48 | } else {
49 | fmt.Fprintf(w, "Error occurred while creating record in database for name :: %s", name[0])
50 | }
51 | }
52 |
53 | func main() {
54 | router := mux.NewRouter()
55 | router.HandleFunc("/employee/create", createRecord).Methods("POST")
56 | defer db.Close()
57 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
58 | if err != nil {
59 | log.Fatal("error starting http server : ", err)
60 | return
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/chapter04/delete-record-mongodb.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 |
8 | "github.com/gorilla/mux"
9 |
10 | mgo "gopkg.in/mgo.v2"
11 | "gopkg.in/mgo.v2/bson"
12 | )
13 |
14 | const (
15 | CONN_HOST = "localhost"
16 | CONN_PORT = "8080"
17 | MONGO_DB_URL = "127.0.0.1"
18 | )
19 |
20 | var session *mgo.Session
21 | var connectionError error
22 |
23 | type Employee struct {
24 | Id int `json:"uid"`
25 | Name string `json:"name"`
26 | }
27 |
28 | func init() {
29 | session, connectionError = mgo.Dial(MONGO_DB_URL)
30 | if connectionError != nil {
31 | log.Fatal("error connecting to database :: ", connectionError)
32 | }
33 | session.SetMode(mgo.Monotonic, true)
34 | }
35 |
36 | func deleteDocument(w http.ResponseWriter, r *http.Request) {
37 | vals := r.URL.Query()
38 | name, ok := vals["name"]
39 | if ok {
40 | log.Print("going to delete document in database for name :: ", name[0])
41 | collection := session.DB("mydb").C("employee")
42 | removeErr := collection.Remove(bson.M{"name": name[0]})
43 | if removeErr != nil {
44 | log.Print("error removing document from database :: ", removeErr)
45 | return
46 | }
47 | fmt.Fprintf(w, "Document with name %s is deleted from database", name[0])
48 | } else {
49 | fmt.Fprintf(w, "Error occurred while deleting document in database for name :: %s", name[0])
50 | }
51 | }
52 |
53 | func main() {
54 | router := mux.NewRouter()
55 | router.HandleFunc("/employee/delete", deleteDocument).Methods("DELETE")
56 | defer session.Close()
57 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
58 | if err != nil {
59 | log.Fatal("error starting http server :: ", err)
60 | return
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/chapter04/delete-record-mysql.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "log"
7 | "net/http"
8 |
9 | _ "github.com/go-sql-driver/mysql"
10 | "github.com/gorilla/mux"
11 | )
12 |
13 | const (
14 | CONN_HOST = "localhost"
15 | CONN_PORT = "8080"
16 | DRIVER_NAME = "mysql"
17 | DATA_SOURCE_NAME = "root:password@/mydb"
18 | )
19 |
20 | var db *sql.DB
21 | var connectionError error
22 |
23 | func init() {
24 | db, connectionError = sql.Open(DRIVER_NAME, DATA_SOURCE_NAME)
25 | if connectionError != nil {
26 | log.Fatal("error connecting to database :: ", connectionError)
27 | }
28 | }
29 |
30 | func deleteRecord(w http.ResponseWriter, r *http.Request) {
31 | vals := r.URL.Query()
32 | name, ok := vals["name"]
33 | if ok {
34 | log.Print("going to delete record in database for name :: ", name[0])
35 | stmt, err := db.Prepare("DELETE from employee where name=?")
36 | if err != nil {
37 | log.Print("error occurred while preparing query :: ", err)
38 | return
39 | }
40 | result, err := stmt.Exec(name[0])
41 | if err != nil {
42 | log.Print("error occurred while executing query :: ", err)
43 | return
44 | }
45 | rowsAffected, err := result.RowsAffected()
46 | fmt.Fprintf(w, "Number of rows deleted in database are :: %d", rowsAffected)
47 | } else {
48 | fmt.Fprintf(w, "Error occurred while deleting record in database for name %s", name[0])
49 | }
50 | }
51 |
52 | func main() {
53 | router := mux.NewRouter()
54 | router.HandleFunc("/employee/delete", deleteRecord).Methods("DELETE")
55 | defer db.Close()
56 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
57 | if err != nil {
58 | log.Fatal("error starting http server :: ", err)
59 | return
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/chapter04/read-record-mongodb.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "log"
6 | "net/http"
7 |
8 | "github.com/gorilla/mux"
9 |
10 | mgo "gopkg.in/mgo.v2"
11 | "gopkg.in/mgo.v2/bson"
12 | )
13 |
14 | const (
15 | CONN_HOST = "localhost"
16 | CONN_PORT = "8080"
17 | MONGO_DB_URL = "127.0.0.1"
18 | )
19 |
20 | var session *mgo.Session
21 | var connectionError error
22 |
23 | func init() {
24 | session, connectionError = mgo.Dial(MONGO_DB_URL)
25 | if connectionError != nil {
26 | log.Fatal("error connecting to database :: ", connectionError)
27 | }
28 | session.SetMode(mgo.Monotonic, true)
29 | }
30 |
31 | type Employee struct {
32 | Id int `json:"uid"`
33 | Name string `json:"name"`
34 | }
35 |
36 | func readDocuments(w http.ResponseWriter, r *http.Request) {
37 | log.Print("reading documents from database")
38 | var employees []Employee
39 |
40 | collection := session.DB("mydb").C("employee")
41 |
42 | err := collection.Find(bson.M{}).All(&employees)
43 | if err != nil {
44 | log.Print("error occurred while reading documents from database :: ", err)
45 | return
46 | }
47 | json.NewEncoder(w).Encode(employees)
48 | }
49 |
50 | func main() {
51 | router := mux.NewRouter()
52 | router.HandleFunc("/employees", readDocuments).Methods("GET")
53 | defer session.Close()
54 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
55 | if err != nil {
56 | log.Fatal("error starting http server :: ", err)
57 | return
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/chapter04/read-record-mysql.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "database/sql"
5 | "encoding/json"
6 | "log"
7 | "net/http"
8 |
9 | _ "github.com/go-sql-driver/mysql"
10 | "github.com/gorilla/mux"
11 | )
12 |
13 | const (
14 | CONN_HOST = "localhost"
15 | CONN_PORT = "8080"
16 | DRIVER_NAME = "mysql"
17 | DATA_SOURCE_NAME = "root:password@/mydb"
18 | )
19 |
20 | var db *sql.DB
21 | var connectionError error
22 |
23 | func init() {
24 | db, connectionError = sql.Open(DRIVER_NAME, DATA_SOURCE_NAME)
25 | if connectionError != nil {
26 | log.Fatal("error connecting to database : ", connectionError)
27 | }
28 | }
29 |
30 | type Employee struct {
31 | Id int `json:"uid"`
32 | Name string `json:"name"`
33 | }
34 |
35 | func readRecords(w http.ResponseWriter, r *http.Request) {
36 | log.Print("reading records from database")
37 | rows, err := db.Query("SELECT * FROM employee")
38 |
39 | if err != nil {
40 | log.Print("error executing select query :: ", err)
41 | return
42 | }
43 | employees := []Employee{}
44 | for rows.Next() {
45 | var uid int
46 | var name string
47 | err = rows.Scan(&uid, &name)
48 | employee := Employee{Id: uid, Name: name}
49 | employees = append(employees, employee)
50 | }
51 | json.NewEncoder(w).Encode(employees)
52 | }
53 |
54 | func main() {
55 | router := mux.NewRouter()
56 | router.HandleFunc("/employees", readRecords).Methods("GET")
57 | defer db.Close()
58 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
59 | if err != nil {
60 | log.Fatal("error starting http server : ", err)
61 | return
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/chapter04/update-record-mongodb.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 | "strconv"
8 |
9 | "github.com/gorilla/mux"
10 |
11 | mgo "gopkg.in/mgo.v2"
12 | "gopkg.in/mgo.v2/bson"
13 | )
14 |
15 | const (
16 | CONN_HOST = "localhost"
17 | CONN_PORT = "8080"
18 | MONGO_DB_URL = "127.0.0.1"
19 | )
20 |
21 | var session *mgo.Session
22 | var connectionError error
23 |
24 | type Employee struct {
25 | Id int `json:"uid"`
26 | Name string `json:"name"`
27 | }
28 |
29 | func init() {
30 | session, connectionError = mgo.Dial(MONGO_DB_URL)
31 | if connectionError != nil {
32 | log.Fatal("error connecting to database :: ", connectionError)
33 | }
34 | session.SetMode(mgo.Monotonic, true)
35 | }
36 |
37 | func updateDocument(w http.ResponseWriter, r *http.Request) {
38 | vars := mux.Vars(r)
39 | id := vars["id"]
40 |
41 | vals := r.URL.Query()
42 | name, ok := vals["name"]
43 |
44 | if ok {
45 | employeeId, err := strconv.Atoi(id)
46 | if err != nil {
47 | log.Print("error converting string id to int :: ", err)
48 | return
49 | }
50 | log.Print("going to update document in database for id :: ", id)
51 | collection := session.DB("mydb").C("employee")
52 | var changeInfo *mgo.ChangeInfo
53 | changeInfo, err = collection.Upsert(bson.M{"id": employeeId}, &Employee{employeeId, name[0]})
54 | if err != nil {
55 | log.Print("error occurred while updating record in database :: ", err)
56 | return
57 | }
58 | fmt.Fprintf(w, "Number of documents updated in database are :: %d", changeInfo.Updated)
59 | } else {
60 | fmt.Fprintf(w, "Error occurred while updating document in database for id :: %s", id)
61 | }
62 | }
63 |
64 | func main() {
65 | router := mux.NewRouter()
66 | router.HandleFunc("/employee/update/{id}", updateDocument).Methods("PUT")
67 | defer session.Close()
68 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
69 | if err != nil {
70 | log.Fatal("error starting http server :: ", err)
71 | return
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/chapter04/update-record-mysql.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 | "log"
7 | "net/http"
8 |
9 | _ "github.com/go-sql-driver/mysql"
10 | "github.com/gorilla/mux"
11 | )
12 |
13 | const (
14 | CONN_HOST = "localhost"
15 | CONN_PORT = "8080"
16 | DRIVER_NAME = "mysql"
17 | DATA_SOURCE_NAME = "root:password@/mydb"
18 | )
19 |
20 | var db *sql.DB
21 | var connectionError error
22 |
23 | func init() {
24 | db, connectionError = sql.Open(DRIVER_NAME, DATA_SOURCE_NAME)
25 | if connectionError != nil {
26 | log.Fatal("error connecting to database :: ", connectionError)
27 | }
28 | }
29 |
30 | type Employee struct {
31 | Id int `json:"uid"`
32 | Name string `json:"name"`
33 | }
34 |
35 | func updateRecord(w http.ResponseWriter, r *http.Request) {
36 | vars := mux.Vars(r)
37 | id := vars["id"]
38 |
39 | vals := r.URL.Query()
40 | name, ok := vals["name"]
41 |
42 | if ok {
43 | log.Print("going to update record in database for id :: ", id)
44 | stmt, err := db.Prepare("UPDATE employee SET name=? where uid=?")
45 | if err != nil {
46 | log.Print("error occurred while preparing query :: ", err)
47 | return
48 | }
49 | result, err := stmt.Exec(name[0], id)
50 | if err != nil {
51 | log.Print("error occurred while executing query :: ", err)
52 | return
53 | }
54 | rowsAffected, err := result.RowsAffected()
55 | fmt.Fprintf(w, "Number of rows updated in database are :: %d", rowsAffected)
56 | } else {
57 | fmt.Fprintf(w, "Error occurred while updating record in database for id :: %s", id)
58 | }
59 | }
60 |
61 | func main() {
62 | router := mux.NewRouter()
63 | router.HandleFunc("/employee/update/{id}", updateRecord).Methods("PUT")
64 | defer db.Close()
65 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
66 | if err != nil {
67 | log.Fatal("error starting http server :: ", err)
68 | return
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/chapter05/angularjs-client/assets/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | AngularJs Client
6 |
7 |
8 |
9 |
10 |
11 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter05/angularjs-client/assets/main.js:
--------------------------------------------------------------------------------
1 | var myapp = angular.module('myapp', []);
2 | myapp.controller('employeeController', function ($scope, $http) {
3 | $scope.addEmployee = function (id, firstName, lastName) {
4 | var data = {
5 | id: id,
6 | firstName: firstName,
7 | lastName: lastName
8 | };
9 | $http.post('/employee/add', data).then(function (response) {
10 | if (response.data)
11 | $scope.message = "Post Data Submitted Successfully!";
12 | });
13 | };
14 | });
15 |
--------------------------------------------------------------------------------
/chapter05/angularjs-client/server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "log"
6 | "net/http"
7 |
8 | "github.com/gorilla/mux"
9 | )
10 |
11 | const (
12 | CONN_HOST = "localhost"
13 | CONN_PORT = "8080"
14 | )
15 |
16 | type Route struct {
17 | Name string
18 | Method string
19 | Pattern string
20 | HandlerFunc http.HandlerFunc
21 | }
22 |
23 | type Routes []Route
24 |
25 | var routes = Routes{
26 | Route{
27 | "getEmployees",
28 | "GET",
29 | "/employees",
30 | getEmployees,
31 | },
32 | Route{
33 | "addEmployee",
34 | "POST",
35 | "/employee/add",
36 | addEmployee,
37 | },
38 | }
39 |
40 | type Employee struct {
41 | Id string `json:"id"`
42 | FirstName string `json:"firstName"`
43 | LastName string `json:"lastName"`
44 | }
45 |
46 | type Employees []Employee
47 |
48 | var employees []Employee
49 |
50 | func init() {
51 | employees = Employees{
52 | Employee{Id: "1", FirstName: "Foo", LastName: "Bar"},
53 | Employee{Id: "2", FirstName: "Baz", LastName: "Qux"},
54 | }
55 | }
56 |
57 | func getEmployees(w http.ResponseWriter, r *http.Request) {
58 | json.NewEncoder(w).Encode(employees)
59 | }
60 |
61 | func addEmployee(w http.ResponseWriter, r *http.Request) {
62 | employee := Employee{}
63 | err := json.NewDecoder(r.Body).Decode(&employee)
64 | if err != nil {
65 | log.Print("error occurred while decoding employee data :: ", err)
66 | return
67 | }
68 | log.Printf("adding employee id :: %s with firstName as :: %s and lastName as :: %s ", employee.Id, employee.FirstName, employee.LastName)
69 | employees = append(employees, Employee{Id: employee.Id, FirstName: employee.FirstName, LastName: employee.LastName})
70 | json.NewEncoder(w).Encode(employees)
71 | }
72 |
73 | func AddRoutes(router *mux.Router) *mux.Router {
74 | for _, route := range routes {
75 | router.
76 | Methods(route.Method).
77 | Path(route.Pattern).
78 | Name(route.Name).
79 | Handler(route.HandlerFunc)
80 | }
81 | return router
82 | }
83 |
84 | func main() {
85 | muxRouter := mux.NewRouter().StrictSlash(true)
86 | router := AddRoutes(muxRouter)
87 | router.PathPrefix("/").Handler(http.FileServer(http.Dir("./assets/")))
88 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
89 | if err != nil {
90 | log.Fatal("error starting http server :: ", err)
91 | return
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/chapter05/http-rest-client.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "log"
7 | "net/http"
8 |
9 | "github.com/gorilla/mux"
10 |
11 | resty "gopkg.in/resty.v1"
12 | )
13 |
14 | const (
15 | CONN_HOST = "localhost"
16 | CONN_PORT = "8090"
17 | )
18 |
19 | const WEB_SERVICE_HOST string = "http://localhost:8080"
20 |
21 | type Employee struct {
22 | Id string `json:"id"`
23 | FirstName string `json:"firstName"`
24 | LastName string `json:"lastName"`
25 | }
26 |
27 | func getEmployees(w http.ResponseWriter, r *http.Request) {
28 | response, err := resty.R().Get(WEB_SERVICE_HOST + "/employees")
29 | if err != nil {
30 | log.Print("error getting data from the web service :: ", err)
31 | return
32 | }
33 | printOutput(response, err)
34 | fmt.Fprintf(w, response.String())
35 | }
36 |
37 | func addEmployee(w http.ResponseWriter, r *http.Request) {
38 | employee := Employee{}
39 | decodingErr := json.NewDecoder(r.Body).Decode(&employee)
40 | if decodingErr != nil {
41 | log.Print("error occurred while decoding employee data :: ", decodingErr)
42 | return
43 | }
44 | log.Printf("adding employee id :: %s with firstName as :: %s and lastName as :: %s ", employee.Id, employee.FirstName, employee.LastName)
45 |
46 | response, err := resty.R().
47 | SetHeader("Content-Type", "application/json").
48 | SetBody(Employee{Id: employee.Id, FirstName: employee.FirstName, LastName: employee.LastName}).
49 | Post(WEB_SERVICE_HOST + "/employee/add")
50 |
51 | if err != nil {
52 | log.Print("error occurred while adding employee :: ", err)
53 | return
54 | }
55 | printOutput(response, err)
56 | fmt.Fprintf(w, response.String())
57 | }
58 |
59 | func updateEmployee(w http.ResponseWriter, r *http.Request) {
60 | employee := Employee{}
61 | decodingErr := json.NewDecoder(r.Body).Decode(&employee)
62 | if decodingErr != nil {
63 | log.Print("error occurred while decoding employee data :: ", decodingErr)
64 | return
65 | }
66 | log.Printf("updating employee id :: %s with firstName as :: %s and lastName as :: %s ", employee.Id, employee.FirstName, employee.LastName)
67 | response, err := resty.R().
68 | SetBody(Employee{Id: employee.Id, FirstName: employee.FirstName, LastName: employee.LastName}).
69 | Put(WEB_SERVICE_HOST + "/employee/update")
70 |
71 | if err != nil {
72 | log.Print("error occurred while updating employee :: ", err)
73 | return
74 | }
75 | printOutput(response, err)
76 | fmt.Fprintf(w, response.String())
77 | }
78 |
79 | func deleteEmployee(w http.ResponseWriter, r *http.Request) {
80 | employee := Employee{}
81 | decodingErr := json.NewDecoder(r.Body).Decode(&employee)
82 | if decodingErr != nil {
83 | log.Print("error occurred while decoding employee data :: ", decodingErr)
84 | return
85 | }
86 | log.Printf("deleting employee id :: %s with firstName as :: %s and lastName as :: %s ", employee.Id, employee.FirstName, employee.LastName)
87 | response, err := resty.R().
88 | SetBody(Employee{Id: employee.Id, FirstName: employee.FirstName, LastName: employee.LastName}).
89 | Delete(WEB_SERVICE_HOST + "/employee/delete")
90 |
91 | if err != nil {
92 | log.Print("error occurred while deleting employee :: ", err)
93 | return
94 | }
95 | printOutput(response, err)
96 | fmt.Fprintf(w, response.String())
97 | }
98 |
99 | func printOutput(resp *resty.Response, err error) {
100 | log.Println(resp, err)
101 | }
102 |
103 | func main() {
104 | router := mux.NewRouter().StrictSlash(false)
105 | router.HandleFunc("/employees", getEmployees).Methods("GET")
106 | employee := router.PathPrefix("/employee").Subrouter()
107 | employee.HandleFunc("/add", addEmployee).Methods("POST")
108 | employee.HandleFunc("/update", updateEmployee).Methods("PUT")
109 | employee.HandleFunc("/delete", deleteEmployee).Methods("DELETE")
110 |
111 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
112 | if err != nil {
113 | log.Fatal("error starting http server : ", err)
114 | return
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/chapter05/http-rest-delete.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "log"
6 | "net/http"
7 |
8 | "github.com/gorilla/mux"
9 | )
10 |
11 | const (
12 | CONN_HOST = "localhost"
13 | CONN_PORT = "8080"
14 | )
15 |
16 | type Route struct {
17 | Name string
18 | Method string
19 | Pattern string
20 | HandlerFunc http.HandlerFunc
21 | }
22 |
23 | type Routes []Route
24 |
25 | var routes = Routes{
26 | Route{
27 | "getEmployees",
28 | "GET",
29 | "/employees",
30 | getEmployees,
31 | },
32 | Route{
33 | "addEmployee",
34 | "POST",
35 | "/employee/add/",
36 | addEmployee,
37 | },
38 | Route{
39 | "deleteEmployee",
40 | "DELETE",
41 | "/employee/delete",
42 | deleteEmployee,
43 | },
44 | }
45 |
46 | type Employee struct {
47 | Id string `json:"id"`
48 | FirstName string `json:"firstName"`
49 | LastName string `json:"lastName"`
50 | }
51 |
52 | type Employees []Employee
53 |
54 | var employees []Employee
55 |
56 | func init() {
57 | employees = Employees{
58 | Employee{Id: "1", FirstName: "Foo", LastName: "Bar"},
59 | Employee{Id: "2", FirstName: "Baz", LastName: "Qux"},
60 | }
61 | }
62 |
63 | func getEmployees(w http.ResponseWriter, r *http.Request) {
64 | json.NewEncoder(w).Encode(employees)
65 | }
66 |
67 | func deleteEmployee(w http.ResponseWriter, r *http.Request) {
68 | employee := Employee{}
69 | err := json.NewDecoder(r.Body).Decode(&employee)
70 | if err != nil {
71 | log.Print("error occurred while decoding employee data :: ", err)
72 | return
73 | }
74 | log.Printf("deleting employee id :: %s with firstName as :: %s and lastName as :: %s ", employee.Id, employee.FirstName, employee.LastName)
75 | index := GetIndex(employee.Id)
76 | employees = append(employees[:index], employees[index+1:]...)
77 | json.NewEncoder(w).Encode(employees)
78 | }
79 |
80 | func GetIndex(id string) int {
81 | for i := 0; i < len(employees); i++ {
82 | if employees[i].Id == id {
83 | return i
84 | }
85 | }
86 | return -1
87 | }
88 |
89 | func addEmployee(w http.ResponseWriter, r *http.Request) {
90 | employee := Employee{}
91 | err := json.NewDecoder(r.Body).Decode(&employee)
92 | if err != nil {
93 | log.Print("error occurred while decoding employee data :: ", err)
94 | return
95 | }
96 | log.Printf("adding employee id :: %s with firstName as :: %s and lastName as :: %s ", employee.Id, employee.FirstName, employee.LastName)
97 | employees = append(employees, Employee{Id: employee.Id, FirstName: employee.FirstName, LastName: employee.LastName})
98 | json.NewEncoder(w).Encode(employees)
99 | }
100 |
101 | func AddRoutes(router *mux.Router) *mux.Router {
102 | for _, route := range routes {
103 | router.
104 | Methods(route.Method).
105 | Path(route.Pattern).
106 | Name(route.Name).
107 | Handler(route.HandlerFunc)
108 | }
109 | return router
110 | }
111 |
112 | func main() {
113 | muxRouter := mux.NewRouter().StrictSlash(true)
114 | router := AddRoutes(muxRouter)
115 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
116 | if err != nil {
117 | log.Fatal("error starting http server :: ", err)
118 | return
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/chapter05/http-rest-get.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "log"
6 | "net/http"
7 |
8 | "github.com/gorilla/mux"
9 | )
10 |
11 | const (
12 | CONN_HOST = "localhost"
13 | CONN_PORT = "8080"
14 | )
15 |
16 | type Route struct {
17 | Name string
18 | Method string
19 | Pattern string
20 | HandlerFunc http.HandlerFunc
21 | }
22 |
23 | type Routes []Route
24 |
25 | var routes = Routes{
26 | Route{
27 | "getEmployees",
28 | "GET",
29 | "/employees",
30 | getEmployees,
31 | },
32 | Route{
33 | "getEmployee",
34 | "GET",
35 | "/employee/{id}",
36 | getEmployee,
37 | },
38 | }
39 |
40 | type Employee struct {
41 | Id string `json:"id"`
42 | FirstName string `json:"firstName"`
43 | LastName string `json:"lastName"`
44 | }
45 |
46 | type Employees []Employee
47 |
48 | var employees []Employee
49 |
50 | func init() {
51 | employees = Employees{
52 | Employee{Id: "1", FirstName: "Foo", LastName: "Bar"},
53 | Employee{Id: "2", FirstName: "Baz", LastName: "Qux"},
54 | }
55 | }
56 |
57 | func getEmployees(w http.ResponseWriter, r *http.Request) {
58 | json.NewEncoder(w).Encode(employees)
59 | }
60 |
61 | func getEmployee(w http.ResponseWriter, r *http.Request) {
62 | vars := mux.Vars(r)
63 | id := vars["id"]
64 |
65 | for _, employee := range employees {
66 | if employee.Id == id {
67 | if err := json.NewEncoder(w).Encode(employee); err != nil {
68 | log.Print("error getting requested employee :: ", err)
69 | }
70 | }
71 | }
72 | }
73 |
74 | func AddRoutes(router *mux.Router) *mux.Router {
75 | for _, route := range routes {
76 | router.
77 | Methods(route.Method).
78 | Path(route.Pattern).
79 | Name(route.Name).
80 | Handler(route.HandlerFunc)
81 | }
82 | return router
83 | }
84 |
85 | func main() {
86 | muxRouter := mux.NewRouter().StrictSlash(true)
87 | router := AddRoutes(muxRouter)
88 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
89 | if err != nil {
90 | log.Fatal("error starting http server :: ", err)
91 | return
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/chapter05/http-rest-post.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "log"
6 | "net/http"
7 |
8 | "github.com/gorilla/mux"
9 | )
10 |
11 | const (
12 | CONN_HOST = "localhost"
13 | CONN_PORT = "8080"
14 | )
15 |
16 | type Route struct {
17 | Name string
18 | Method string
19 | Pattern string
20 | HandlerFunc http.HandlerFunc
21 | }
22 |
23 | type Routes []Route
24 |
25 | var routes = Routes{
26 | Route{
27 | "getEmployees",
28 | "GET",
29 | "/employees",
30 | getEmployees,
31 | },
32 | Route{
33 | "addEmployee",
34 | "POST",
35 | "/employee/add",
36 | addEmployee,
37 | },
38 | }
39 |
40 | type Employee struct {
41 | Id string `json:"id"`
42 | FirstName string `json:"firstName"`
43 | LastName string `json:"lastName"`
44 | }
45 |
46 | type Employees []Employee
47 |
48 | var employees []Employee
49 |
50 | func init() {
51 | employees = Employees{
52 | Employee{Id: "1", FirstName: "Foo", LastName: "Bar"},
53 | Employee{Id: "2", FirstName: "Baz", LastName: "Qux"},
54 | }
55 | }
56 |
57 | func getEmployees(w http.ResponseWriter, r *http.Request) {
58 | json.NewEncoder(w).Encode(employees)
59 | }
60 |
61 | func addEmployee(w http.ResponseWriter, r *http.Request) {
62 | employee := Employee{}
63 | err := json.NewDecoder(r.Body).Decode(&employee)
64 | if err != nil {
65 | log.Print("error occurred while decoding employee data :: ", err)
66 | return
67 | }
68 | log.Printf("adding employee id :: %s with firstName as :: %s and lastName as :: %s ", employee.Id, employee.FirstName, employee.LastName)
69 | employees = append(employees, Employee{Id: employee.Id, FirstName: employee.FirstName, LastName: employee.LastName})
70 | json.NewEncoder(w).Encode(employees)
71 | }
72 |
73 | func AddRoutes(router *mux.Router) *mux.Router {
74 | for _, route := range routes {
75 | router.
76 | Methods(route.Method).
77 | Path(route.Pattern).
78 | Name(route.Name).
79 | Handler(route.HandlerFunc)
80 | }
81 | return router
82 | }
83 |
84 | func main() {
85 | muxRouter := mux.NewRouter().StrictSlash(true)
86 | router := AddRoutes(muxRouter)
87 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
88 | if err != nil {
89 | log.Fatal("error starting http server :: ", err)
90 | return
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/chapter05/http-rest-put.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "log"
6 | "net/http"
7 |
8 | "github.com/gorilla/mux"
9 | )
10 |
11 | const (
12 | CONN_HOST = "localhost"
13 | CONN_PORT = "8080"
14 | )
15 |
16 | type Route struct {
17 | Name string
18 | Method string
19 | Pattern string
20 | HandlerFunc http.HandlerFunc
21 | }
22 |
23 | type Routes []Route
24 |
25 | var routes = Routes{
26 | Route{
27 | "getEmployees",
28 | "GET",
29 | "/employees",
30 | getEmployees,
31 | },
32 | Route{
33 | "addEmployee",
34 | "POST",
35 | "/employee/add",
36 | addEmployee,
37 | },
38 | Route{
39 | "updateEmployee",
40 | "PUT",
41 | "/employee/update",
42 | updateEmployee,
43 | },
44 | }
45 |
46 | type Employee struct {
47 | Id string `json:"id"`
48 | FirstName string `json:"firstName"`
49 | LastName string `json:"lastName"`
50 | }
51 |
52 | type Employees []Employee
53 |
54 | var employees []Employee
55 |
56 | func init() {
57 | employees = Employees{
58 | Employee{Id: "1", FirstName: "Foo", LastName: "Bar"},
59 | Employee{Id: "2", FirstName: "Baz", LastName: "Qux"},
60 | }
61 | }
62 |
63 | func getEmployees(w http.ResponseWriter, r *http.Request) {
64 | json.NewEncoder(w).Encode(employees)
65 | }
66 |
67 | func updateEmployee(w http.ResponseWriter, r *http.Request) {
68 | employee := Employee{}
69 | err := json.NewDecoder(r.Body).Decode(&employee)
70 | if err != nil {
71 | log.Print("error occurred while decoding employee data :: ", err)
72 | return
73 | }
74 | var isUpsert = true
75 | for idx, emp := range employees {
76 | if emp.Id == employee.Id {
77 | isUpsert = false
78 | log.Printf("updating employee id :: %s with firstName as :: %s and lastName as:: %s ", employee.Id, employee.FirstName, employee.LastName)
79 | employees[idx].FirstName = employee.FirstName
80 | employees[idx].LastName = employee.LastName
81 | break
82 | }
83 | }
84 | if isUpsert {
85 | log.Printf("upserting employee id :: %s with firstName as :: %s and lastName as:: %s ", employee.Id, employee.FirstName, employee.LastName)
86 | employees = append(employees, Employee{Id: employee.Id, FirstName: employee.FirstName, LastName: employee.LastName})
87 | }
88 | json.NewEncoder(w).Encode(employees)
89 | }
90 |
91 | func addEmployee(w http.ResponseWriter, r *http.Request) {
92 | employee := Employee{}
93 | err := json.NewDecoder(r.Body).Decode(&employee)
94 | if err != nil {
95 | log.Print("error occurred while decoding employee data :: ", err)
96 | return
97 | }
98 | log.Printf("adding employee id :: %d with firstName as :: %s and lastName as :: %s ", employee.Id, employee.FirstName, employee.LastName)
99 | employees = append(employees, Employee{Id: employee.Id, FirstName: employee.FirstName, LastName: employee.LastName})
100 | json.NewEncoder(w).Encode(employees)
101 | }
102 |
103 | func AddRoutes(router *mux.Router) *mux.Router {
104 | for _, route := range routes {
105 | router.
106 | Methods(route.Method).
107 | Path(route.Pattern).
108 | Name(route.Name).
109 | Handler(route.HandlerFunc)
110 | }
111 | return router
112 | }
113 |
114 | func main() {
115 | muxRouter := mux.NewRouter().StrictSlash(true)
116 | router := AddRoutes(muxRouter)
117 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
118 | if err != nil {
119 | log.Fatal("error starting http server :: ", err)
120 | return
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/chapter05/http-rest-versioning.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "log"
6 | "net/http"
7 | "strings"
8 |
9 | "github.com/gorilla/mux"
10 | )
11 |
12 | const (
13 | CONN_HOST = "localhost"
14 | CONN_PORT = "8080"
15 | )
16 |
17 | type Route struct {
18 | Name string
19 | Method string
20 | Pattern string
21 | HandlerFunc http.HandlerFunc
22 | }
23 |
24 | type Routes []Route
25 |
26 | var routes = Routes{
27 | Route{
28 | "getEmployees",
29 | "GET",
30 | "/employees",
31 | getEmployees,
32 | },
33 | }
34 |
35 | type Employee struct {
36 | Id string `json:"id"`
37 | FirstName string `json:"firstName"`
38 | LastName string `json:"lastName"`
39 | }
40 |
41 | type Employees []Employee
42 |
43 | var employees []Employee
44 | var employeesV1 []Employee
45 | var employeesV2 []Employee
46 |
47 | func init() {
48 |
49 | employees = Employees{
50 | Employee{Id: "1", FirstName: "Foo", LastName: "Bar"},
51 | }
52 |
53 | employeesV1 = Employees{
54 | Employee{Id: "1", FirstName: "Foo", LastName: "Bar"},
55 | Employee{Id: "2", FirstName: "Baz", LastName: "Qux"},
56 | }
57 |
58 | employeesV2 = Employees{
59 | Employee{Id: "1", FirstName: "Baz", LastName: "Qux"},
60 | Employee{Id: "2", FirstName: "Quux", LastName: "Quuz"},
61 | }
62 | }
63 |
64 | func getEmployees(w http.ResponseWriter, r *http.Request) {
65 | if strings.HasPrefix(r.URL.Path, "/v1") {
66 | json.NewEncoder(w).Encode(employeesV1)
67 | } else if strings.HasPrefix(r.URL.Path, "/v2") {
68 | json.NewEncoder(w).Encode(employeesV2)
69 | } else {
70 | json.NewEncoder(w).Encode(employees)
71 | }
72 | }
73 |
74 | func AddRoutes(router *mux.Router) *mux.Router {
75 | for _, route := range routes {
76 | router.
77 | Methods(route.Method).
78 | Path(route.Pattern).
79 | Name(route.Name).
80 | Handler(route.HandlerFunc)
81 | }
82 | return router
83 | }
84 |
85 | func main() {
86 | muxRouter := mux.NewRouter().StrictSlash(true)
87 | router := AddRoutes(muxRouter)
88 | // v1
89 | AddRoutes(muxRouter.PathPrefix("/v1").Subrouter())
90 | // v2
91 | AddRoutes(muxRouter.PathPrefix("/v2").Subrouter())
92 |
93 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
94 | if err != nil {
95 | log.Fatal("error starting http server :: ", err)
96 | return
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/chapter05/reactjs-client/app/components/add-employee.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component, PropTypes } from 'react'
2 |
3 | export default class AddEmployee extends React.Component {
4 |
5 | render(){
6 | return (
7 |
8 |
9 | this.handleClick(e)}>
10 | Add
11 |
12 |
13 | )
14 |
15 | }
16 | handleClick(e) {
17 | const node = this.refs.input
18 | const text = node.value.trim()
19 | this.props.addEmployee(text)
20 | node.value = ''
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/chapter05/reactjs-client/app/components/employee-app.jsx:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const React = require('react');
3 | var axios = require('axios');
4 |
5 | import EmployeeList from './employee-list.jsx'
6 | import AddEmployee from './add-employee.jsx'
7 |
8 | export default class EmployeeApp extends React.Component {
9 |
10 | constructor(props) {
11 | super(props);
12 | this.state = {employees: []};
13 | this.addEmployee = this.addEmployee.bind(this);
14 | this.Axios = axios.create({
15 | headers: {'content-type': 'application/json'}
16 | });
17 | }
18 |
19 | componentDidMount() {
20 | let _this = this;
21 | this.Axios.get('/employees')
22 | .then(function (response) {
23 | _this.setState({employees: response.data});
24 | })
25 | .catch(function (error) { });
26 | }
27 |
28 | addEmployee(employeeName){
29 | let _this = this;
30 | this.Axios.post('/employee/add', {
31 | firstName: employeeName
32 | })
33 | .then(function (response) {
34 | _this.setState({employees: response.data});
35 | })
36 | .catch(function (error) { });
37 | }
38 | render() {
39 | return (
40 |
44 | )
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/chapter05/reactjs-client/app/components/employee-list.jsx:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | import Employee from './employee.jsx'
3 |
4 | export default class EmployeeList extends React.Component{
5 |
6 | render() {
7 | var employees = this.props.employees.map((employee, i) =>
8 |
9 | );
10 |
11 | return (
12 |
13 |
14 |
15 | FirstName
16 |
17 | {employees}
18 |
19 |
20 | )
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/chapter05/reactjs-client/app/components/employee.jsx:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | export default class Employee extends React.Component{
4 | render() {
5 | return (
6 |
7 | {this.props.employee.firstName}
8 |
9 | )
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/chapter05/reactjs-client/app/main.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const React = require('react');
3 | const ReactDOM = require('react-dom')
4 |
5 | import EmployeeApp from './components/employee-app.jsx'
6 |
7 | ReactDOM.render(
8 | ,
9 | document.getElementById('react')
10 | )
11 |
--------------------------------------------------------------------------------
/chapter05/reactjs-client/assets/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ReactJS Client
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/chapter05/reactjs-client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "reactjs-client",
3 | "version": "1.0.0",
4 | "description": "ReactJs Client",
5 | "keywords": [
6 | "react"
7 | ],
8 | "author": "Arpit Aggarwal",
9 | "dependencies": {
10 | "axios": "^0.18.0",
11 | "react": "^16.2.0",
12 | "react-dom": "^16.2.0",
13 | "react-router-dom": "^4.2.2",
14 | "webpack": "^4.2.0",
15 | "webpack-cli": "^2.0.9",
16 | "lodash": "^4.17.5"
17 | },
18 | "scripts": {
19 | "build": "webpack",
20 | "watch": "webpack --watch -d"
21 | },
22 | "devDependencies": {
23 | "babel-core": "^6.18.2",
24 | "babel-loader": "^7.1.4",
25 | "babel-polyfill": "^6.16.0",
26 | "babel-preset-es2015": "^6.18.0",
27 | "babel-preset-react": "^6.16.0"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/chapter05/reactjs-client/server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "log"
6 | "net/http"
7 |
8 | "github.com/gorilla/mux"
9 | )
10 |
11 | const (
12 | CONN_HOST = "localhost"
13 | CONN_PORT = "8080"
14 | )
15 |
16 | type Route struct {
17 | Name string
18 | Method string
19 | Pattern string
20 | HandlerFunc http.HandlerFunc
21 | }
22 |
23 | type Routes []Route
24 |
25 | var routes = Routes{
26 | Route{
27 | "getEmployees",
28 | "GET",
29 | "/employees",
30 | getEmployees,
31 | },
32 | Route{
33 | "addEmployee",
34 | "POST",
35 | "/employee/add",
36 | addEmployee,
37 | },
38 | }
39 |
40 | type Employee struct {
41 | Id string `json:"id"`
42 | FirstName string `json:"firstName"`
43 | LastName string `json:"lastName"`
44 | }
45 |
46 | type Employees []Employee
47 |
48 | var employees []Employee
49 |
50 | func init() {
51 | employees = Employees{
52 | Employee{Id: "1", FirstName: "Foo", LastName: "Bar"},
53 | Employee{Id: "2", FirstName: "Baz", LastName: "Qux"},
54 | }
55 | }
56 |
57 | func getEmployees(w http.ResponseWriter, r *http.Request) {
58 | json.NewEncoder(w).Encode(employees)
59 | }
60 |
61 | func addEmployee(w http.ResponseWriter, r *http.Request) {
62 | employee := Employee{}
63 | err := json.NewDecoder(r.Body).Decode(&employee)
64 | if err != nil {
65 | log.Print("error occurred while decoding employee data :: ", err)
66 | return
67 | }
68 | log.Printf("adding employee id :: %s with firstName as :: %s and lastName as :: %s ", employee.Id, employee.FirstName, employee.LastName)
69 | employees = append(employees, Employee{Id: employee.Id, FirstName: employee.FirstName, LastName: employee.LastName})
70 | json.NewEncoder(w).Encode(employees)
71 | }
72 |
73 | func AddRoutes(router *mux.Router) *mux.Router {
74 | for _, route := range routes {
75 | router.
76 | Methods(route.Method).
77 | Path(route.Pattern).
78 | Name(route.Name).
79 | Handler(route.HandlerFunc)
80 | }
81 | return router
82 | }
83 |
84 | func main() {
85 | muxRouter := mux.NewRouter().StrictSlash(true)
86 | router := AddRoutes(muxRouter)
87 | router.PathPrefix("/").Handler(http.FileServer(http.Dir("./assets/")))
88 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
89 | if err != nil {
90 | log.Fatal("error starting http server :: ", err)
91 | return
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/chapter05/reactjs-client/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 |
3 | module.exports = {
4 | resolve: {
5 | extensions: ['.js', '.jsx']
6 | },
7 | mode: 'development',
8 | entry: './app/main.js',
9 | cache: true,
10 | output: {
11 | path: __dirname,
12 | filename: './assets/script.js'
13 | },
14 | module: {
15 | rules: [
16 | {
17 | test: path.join(__dirname, '.'),
18 | exclude: /(node_modules)/,
19 | loader: 'babel-loader',
20 | query: {
21 | cacheDirectory: true,
22 | presets: ['es2015', 'react']
23 | }
24 | }
25 | ]
26 | }
27 | };
28 |
--------------------------------------------------------------------------------
/chapter05/vuejs-client/assets/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | VueJs Client
4 |
5 |
6 |
7 |
8 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/chapter05/vuejs-client/assets/main.js:
--------------------------------------------------------------------------------
1 | var vue_det = new Vue({
2 | el: '#form',
3 | data: {
4 | message: 'Employee Dashboard',
5 | id: '',
6 | firstName:'',
7 | lastName:''
8 | },
9 | methods: {
10 | addEmployee: function() {
11 | this.$http.post('/employee/add', {
12 | id: this.id,
13 | firstName:this.firstName,
14 | lastName:this.lastName
15 | }).then(response => {
16 | console.log(response);
17 | }, error => {
18 | console.error(error);
19 | });
20 | }}
21 | });
22 |
--------------------------------------------------------------------------------
/chapter05/vuejs-client/server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "log"
6 | "net/http"
7 |
8 | "github.com/gorilla/mux"
9 | )
10 |
11 | const (
12 | CONN_HOST = "localhost"
13 | CONN_PORT = "8080"
14 | )
15 |
16 | type Route struct {
17 | Name string
18 | Method string
19 | Pattern string
20 | HandlerFunc http.HandlerFunc
21 | }
22 |
23 | type Routes []Route
24 |
25 | var routes = Routes{
26 | Route{
27 | "getEmployees",
28 | "GET",
29 | "/employees",
30 | getEmployees,
31 | },
32 | Route{
33 | "addEmployee",
34 | "POST",
35 | "/employee/add",
36 | addEmployee,
37 | },
38 | }
39 |
40 | type Employee struct {
41 | Id string `json:"id"`
42 | FirstName string `json:"firstName"`
43 | LastName string `json:"lastName"`
44 | }
45 |
46 | type Employees []Employee
47 |
48 | var employees []Employee
49 |
50 | func init() {
51 | employees = Employees{
52 | Employee{Id: "1", FirstName: "Foo", LastName: "Bar"},
53 | Employee{Id: "2", FirstName: "Baz", LastName: "Qux"},
54 | }
55 | }
56 |
57 | func getEmployees(w http.ResponseWriter, r *http.Request) {
58 | json.NewEncoder(w).Encode(employees)
59 | }
60 |
61 | func addEmployee(w http.ResponseWriter, r *http.Request) {
62 | employee := Employee{}
63 | err := json.NewDecoder(r.Body).Decode(&employee)
64 | if err != nil {
65 | log.Print("error occurred while decoding employee data :: ", err)
66 | return
67 | }
68 | log.Printf("adding employee id :: %s with firstName as :: %s and lastName as :: %s ", employee.Id, employee.FirstName, employee.LastName)
69 | employees = append(employees, Employee{Id: employee.Id, FirstName: employee.FirstName, LastName: employee.LastName})
70 | json.NewEncoder(w).Encode(employees)
71 | }
72 |
73 | func AddRoutes(router *mux.Router) *mux.Router {
74 | for _, route := range routes {
75 | router.
76 | Methods(route.Method).
77 | Path(route.Pattern).
78 | Name(route.Name).
79 | Handler(route.HandlerFunc)
80 | }
81 | return router
82 | }
83 |
84 | func main() {
85 | muxRouter := mux.NewRouter().StrictSlash(true)
86 | router := AddRoutes(muxRouter)
87 | router.PathPrefix("/").Handler(http.FileServer(http.Dir("./assets/")))
88 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
89 | if err != nil {
90 | log.Fatal("error starting http server :: ", err)
91 | return
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/chapter06/api/greeting-api.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "log"
7 | "strings"
8 |
9 | hello "../proto"
10 | "github.com/micro/go-micro"
11 | api "github.com/micro/micro/api/proto"
12 | )
13 |
14 | type Say struct {
15 | Client hello.SayClient
16 | }
17 |
18 | func (s *Say) Hello(ctx context.Context, req *api.Request, rsp *api.Response) error {
19 | log.Print("Received Say.Hello request - Micro Greeter API")
20 | name, ok := req.Get["name"]
21 | if ok {
22 | response, err := s.Client.Hello(ctx, &hello.Request{
23 | Name: strings.Join(name.Values, " "),
24 | })
25 | if err != nil {
26 | return err
27 | }
28 | message, _ := json.Marshal(map[string]string{
29 | "message": response.Msg,
30 | })
31 | rsp.Body = string(message)
32 | }
33 | return nil
34 | }
35 |
36 | func main() {
37 | service := micro.NewService(
38 | micro.Name("go.micro.api.greeter"),
39 | )
40 | service.Init()
41 | service.Server().Handle(
42 | service.Server().NewHandler(
43 | &Say{Client: hello.NewSayClient("go.micro.service.greeter", service.Client())},
44 | ),
45 | )
46 | if err := service.Run(); err != nil {
47 | log.Fatal("error starting micro api : ", err)
48 | return
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/chapter06/proto/hello.pb.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go. DO NOT EDIT.
2 | // source: hello.proto
3 |
4 | /*
5 | Package hello is a generated protocol buffer package.
6 |
7 | It is generated from these files:
8 | hello.proto
9 |
10 | It has these top-level messages:
11 | Request
12 | Response
13 | */
14 | package hello
15 |
16 | import proto "github.com/golang/protobuf/proto"
17 | import fmt "fmt"
18 | import math "math"
19 |
20 | import (
21 | client "github.com/micro/go-micro/client"
22 | server "github.com/micro/go-micro/server"
23 | context "golang.org/x/net/context"
24 | )
25 |
26 | // Reference imports to suppress errors if they are not otherwise used.
27 | var _ = proto.Marshal
28 | var _ = fmt.Errorf
29 | var _ = math.Inf
30 |
31 | // This is a compile-time assertion to ensure that this generated file
32 | // is compatible with the proto package it is being compiled against.
33 | // A compilation error at this line likely means your copy of the
34 | // proto package needs to be updated.
35 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
36 |
37 | type Request struct {
38 | Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
39 | }
40 |
41 | func (m *Request) Reset() { *m = Request{} }
42 | func (m *Request) String() string { return proto.CompactTextString(m) }
43 | func (*Request) ProtoMessage() {}
44 | func (*Request) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
45 |
46 | func (m *Request) GetName() string {
47 | if m != nil {
48 | return m.Name
49 | }
50 | return ""
51 | }
52 |
53 | type Response struct {
54 | Msg string `protobuf:"bytes,1,opt,name=msg" json:"msg,omitempty"`
55 | }
56 |
57 | func (m *Response) Reset() { *m = Response{} }
58 | func (m *Response) String() string { return proto.CompactTextString(m) }
59 | func (*Response) ProtoMessage() {}
60 | func (*Response) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
61 |
62 | func (m *Response) GetMsg() string {
63 | if m != nil {
64 | return m.Msg
65 | }
66 | return ""
67 | }
68 |
69 | func init() {
70 | proto.RegisterType((*Request)(nil), "Request")
71 | proto.RegisterType((*Response)(nil), "Response")
72 | }
73 |
74 | // Reference imports to suppress errors if they are not otherwise used.
75 | var _ context.Context
76 | var _ client.Option
77 | var _ server.Option
78 |
79 | // Client API for Say service
80 |
81 | type SayClient interface {
82 | Hello(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
83 | }
84 |
85 | type sayClient struct {
86 | c client.Client
87 | serviceName string
88 | }
89 |
90 | func NewSayClient(serviceName string, c client.Client) SayClient {
91 | if c == nil {
92 | c = client.NewClient()
93 | }
94 | if len(serviceName) == 0 {
95 | serviceName = "say"
96 | }
97 | return &sayClient{
98 | c: c,
99 | serviceName: serviceName,
100 | }
101 | }
102 |
103 | func (c *sayClient) Hello(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
104 | req := c.c.NewRequest(c.serviceName, "Say.Hello", in)
105 | out := new(Response)
106 | err := c.c.Call(ctx, req, out, opts...)
107 | if err != nil {
108 | return nil, err
109 | }
110 | return out, nil
111 | }
112 |
113 | // Server API for Say service
114 |
115 | type SayHandler interface {
116 | Hello(context.Context, *Request, *Response) error
117 | }
118 |
119 | func RegisterSayHandler(s server.Server, hdlr SayHandler, opts ...server.HandlerOption) {
120 | s.Handle(s.NewHandler(&Say{hdlr}, opts...))
121 | }
122 |
123 | type Say struct {
124 | SayHandler
125 | }
126 |
127 | func (h *Say) Hello(ctx context.Context, in *Request, out *Response) error {
128 | return h.SayHandler.Hello(ctx, in, out)
129 | }
130 |
131 | func init() { proto.RegisterFile("hello.proto", fileDescriptor0) }
132 |
133 | var fileDescriptor0 = []byte{
134 | // 119 bytes of a gzipped FileDescriptorProto
135 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xce, 0x48, 0xcd, 0xc9,
136 | 0xc9, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x57, 0x92, 0xe5, 0x62, 0x0f, 0x4a, 0x2d, 0x2c, 0x4d,
137 | 0x2d, 0x2e, 0x11, 0x12, 0xe2, 0x62, 0xc9, 0x4b, 0xcc, 0x4d, 0x95, 0x60, 0x54, 0x60, 0xd4, 0xe0,
138 | 0x0c, 0x02, 0xb3, 0x95, 0x64, 0xb8, 0x38, 0x82, 0x52, 0x8b, 0x0b, 0xf2, 0xf3, 0x8a, 0x53, 0x85,
139 | 0x04, 0xb8, 0x98, 0x73, 0x8b, 0xd3, 0xa1, 0xd2, 0x20, 0xa6, 0x91, 0x2a, 0x17, 0x73, 0x70, 0x62,
140 | 0xa5, 0x90, 0x1c, 0x17, 0xab, 0x07, 0xc8, 0x48, 0x21, 0x0e, 0x3d, 0xa8, 0x59, 0x52, 0x9c, 0x7a,
141 | 0x30, 0x6d, 0x4a, 0x0c, 0x49, 0x6c, 0x60, 0xab, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x70,
142 | 0x5c, 0xda, 0x68, 0x79, 0x00, 0x00, 0x00,
143 | }
144 |
--------------------------------------------------------------------------------
/chapter06/proto/hello.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | service Say {
4 | rpc Hello(Request) returns (Response) {}
5 | }
6 |
7 | message Request {
8 | string name = 1;
9 | }
10 |
11 | message Response {
12 | string msg = 1;
13 | }
14 |
--------------------------------------------------------------------------------
/chapter06/services/first-greeting-service.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "log"
6 | "time"
7 |
8 | hello "../proto"
9 | "github.com/micro/go-micro"
10 | )
11 |
12 | type Say struct{}
13 |
14 | func (s *Say) Hello(ctx context.Context, req *hello.Request, rsp *hello.Response) error {
15 | log.Print("Received Say.Hello request - first greeting service")
16 | rsp.Msg = "Hello " + req.Name
17 | return nil
18 | }
19 |
20 | func main() {
21 | service := micro.NewService(
22 | micro.Name("go.micro.service.greeter"),
23 | micro.RegisterTTL(time.Second*30),
24 | micro.RegisterInterval(time.Second*10),
25 | )
26 | service.Init()
27 | hello.RegisterSayHandler(service.Server(), new(Say))
28 | if err := service.Run(); err != nil {
29 | log.Fatal("error starting service : ", err)
30 | return
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/chapter06/services/second-greeting-service.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "log"
6 | "time"
7 |
8 | hello "../proto"
9 | "github.com/micro/go-micro"
10 | )
11 |
12 | type Say struct{}
13 |
14 | func (s *Say) Hello(ctx context.Context, req *hello.Request, rsp *hello.Response) error {
15 | log.Print("Received Say.Hello request - second greeting service")
16 | rsp.Msg = "Hello " + req.Name
17 | return nil
18 | }
19 |
20 | func main() {
21 | service := micro.NewService(
22 | micro.Name("go.micro.service.greeter"),
23 | micro.RegisterTTL(time.Second*30),
24 | micro.RegisterInterval(time.Second*10),
25 | )
26 | service.Init()
27 | hello.RegisterSayHandler(service.Server(), new(Say))
28 | if err := service.Run(); err != nil {
29 | log.Fatal("error starting service : ", err)
30 | return
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/chapter07/index.html:
--------------------------------------------------------------------------------
1 |
2 | WebSocket Server
3 |
4 |
5 | Send
6 |
7 |
8 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/chapter07/websocket-server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "net/http"
6 |
7 | "github.com/gorilla/websocket"
8 | )
9 |
10 | var clients = make(map[*websocket.Conn]bool)
11 | var broadcast = make(chan Message)
12 |
13 | var upgrader = websocket.Upgrader{}
14 |
15 | type Message struct {
16 | Message string `json:"message"`
17 | }
18 |
19 | func HandleClients(w http.ResponseWriter, r *http.Request) {
20 | go broadcastMessagesToClients()
21 |
22 | websocket, err := upgrader.Upgrade(w, r, nil)
23 | if err != nil {
24 | log.Fatal("error upgrading GET request to a websocket :: ", err)
25 | }
26 |
27 | defer websocket.Close()
28 |
29 | clients[websocket] = true
30 |
31 | for {
32 | var message Message
33 |
34 | err := websocket.ReadJSON(&message)
35 | if err != nil {
36 | log.Printf("error occurred while reading message : %v", err)
37 | delete(clients, websocket)
38 | break
39 | }
40 | broadcast <- message
41 | }
42 | }
43 |
44 | func main() {
45 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
46 | http.ServeFile(w, r, "index.html")
47 | })
48 | http.HandleFunc("/echo", HandleClients)
49 |
50 | err := http.ListenAndServe(":8080", nil)
51 | if err != nil {
52 | log.Fatal("error starting http server :: ", err)
53 | return
54 | }
55 | }
56 |
57 | func broadcastMessagesToClients() {
58 | for {
59 | message := <-broadcast
60 | for client := range clients {
61 | err := client.WriteJSON(message)
62 | if err != nil {
63 | log.Printf("error occurred while writing message to client: %v", err)
64 | client.Close()
65 | delete(clients, client)
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/chapter07/websocket-server_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "net/http"
5 | "net/http/httptest"
6 | "strings"
7 | "testing"
8 |
9 | "github.com/gorilla/websocket"
10 | "github.com/stretchr/testify/assert"
11 | )
12 |
13 | func TestWebSocketServer(t *testing.T) {
14 | server := httptest.NewServer(http.HandlerFunc(HandleClients))
15 | defer server.Close()
16 |
17 | u := "ws" + strings.TrimPrefix(server.URL, "http")
18 |
19 | socket, _, err := websocket.DefaultDialer.Dial(u, nil)
20 | if err != nil {
21 | t.Fatalf("%v", err)
22 | }
23 | defer socket.Close()
24 |
25 | m := Message{Message: "hello"}
26 |
27 | if err := socket.WriteJSON(&m); err != nil {
28 | t.Fatalf("%v", err)
29 | }
30 |
31 | var message Message
32 | err = socket.ReadJSON(&message)
33 | if err != nil {
34 | t.Fatalf("%v", err)
35 | }
36 | assert.Equal(t, "hello", message.Message, "they should be equal")
37 | }
38 |
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/conf/app.conf:
--------------------------------------------------------------------------------
1 | appname = my-first-beego-project
2 | httpport = 8080
3 | runmode = prod
4 | SessionOn = true
5 | SessionProvider = "redis"
6 | SessionProviderConfig = "127.0.0.1:6379"
7 | EnableAdmin = true
8 | AdminAddr = "localhost"
9 | AdminPort = 8088
10 | EnableDocs = true
11 |
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/controllers/cachecontroller.go:
--------------------------------------------------------------------------------
1 | package controllers
2 |
3 | import (
4 | "fmt"
5 | "time"
6 |
7 | "github.com/astaxie/beego"
8 | "github.com/astaxie/beego/cache"
9 | )
10 |
11 | type CacheController struct {
12 | beego.Controller
13 | }
14 |
15 | var beegoCache cache.Cache
16 | var err error
17 |
18 | func init() {
19 | beegoCache, err = cache.NewCache("memory", `{"interval":60}`)
20 | beegoCache.Put("foo", "bar", 100000*time.Second)
21 | }
22 |
23 | func (this *CacheController) GetFromCache() {
24 | foo := beegoCache.Get("foo")
25 | this.Ctx.WriteString("Hello " + fmt.Sprintf("%v", foo))
26 | }
27 |
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/controllers/default.go:
--------------------------------------------------------------------------------
1 | package controllers
2 |
3 | import (
4 | "github.com/astaxie/beego"
5 | )
6 |
7 | type MainController struct {
8 | beego.Controller
9 | }
10 |
11 | func (c *MainController) Get() {
12 | c.Data["Website"] = "beego.me"
13 | c.Data["Email"] = "astaxie@gmail.com"
14 | c.TplName = "index.tpl"
15 | }
16 |
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/controllers/errorcontroller.go:
--------------------------------------------------------------------------------
1 | package controllers
2 |
3 | import "github.com/astaxie/beego"
4 |
5 | type ErrorController struct {
6 | beego.Controller
7 | }
8 |
9 | func (c *ErrorController) Error404() {
10 | c.Data["content"] = "Page Not Found"
11 | c.TplName = "404.tpl"
12 | }
13 |
14 | func (c *ErrorController) Error500() {
15 | c.Data["content"] = "Internal Server Error"
16 | c.TplName = "500.tpl"
17 | }
18 |
19 | func (c *ErrorController) ErrorGeneric() {
20 | c.Data["content"] = "Some Error Occurred"
21 | c.TplName = "genericerror.tpl"
22 | }
23 |
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/controllers/firstcontroller.go:
--------------------------------------------------------------------------------
1 | package controllers
2 |
3 | import "github.com/astaxie/beego"
4 |
5 | type FirstController struct {
6 | beego.Controller
7 | }
8 |
9 | type Employee struct {
10 | Id int `json:"id"`
11 | FirstName string `json:"firstName"`
12 | LastName string `json:"lastName"`
13 | }
14 |
15 | type Employees []Employee
16 |
17 | var employees []Employee
18 |
19 | func init() {
20 | employees = Employees{
21 | Employee{Id: 1, FirstName: "Foo", LastName: "Bar"},
22 | Employee{Id: 2, FirstName: "Baz", LastName: "Qux"},
23 | }
24 | }
25 |
26 | func (this *FirstController) GetEmployees() {
27 | this.Ctx.ResponseWriter.WriteHeader(200)
28 | this.Data["json"] = employees
29 | this.ServeJSON()
30 | }
31 |
32 | func (this *FirstController) Dashbaord() {
33 | this.Data["employees"] = employees
34 | this.TplName = "dashboard.tpl"
35 | }
36 |
37 | func (this *FirstController) GetEmployee() {
38 | var id int
39 | this.Ctx.Input.Bind(&id, "id")
40 | var isEmployeeExist bool
41 | var emps []Employee
42 | for _, employee := range employees {
43 | if employee.Id == id {
44 | emps = append(emps, Employee{Id: employee.Id, FirstName: employee.FirstName, LastName: employee.LastName})
45 | isEmployeeExist = true
46 | break
47 | }
48 | }
49 | if !isEmployeeExist {
50 | this.Abort("Generic")
51 | } else {
52 | this.Data["employees"] = emps
53 | this.TplName = "dashboard.tpl"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/controllers/sessioncontroller.go:
--------------------------------------------------------------------------------
1 | package controllers
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/astaxie/beego"
7 | )
8 |
9 | type SessionController struct {
10 | beego.Controller
11 | }
12 |
13 | func (this *SessionController) Home() {
14 | isAuthenticated := this.GetSession("authenticated")
15 | fmt.Println(isAuthenticated)
16 | if isAuthenticated == nil || isAuthenticated == false {
17 | this.Ctx.WriteString("You are unauthorized to view the page.")
18 | return
19 | }
20 | this.Ctx.ResponseWriter.WriteHeader(200)
21 | this.Ctx.WriteString("Home Page")
22 | }
23 |
24 | func (this *SessionController) Login() {
25 | this.SetSession("authenticated", true)
26 | this.Ctx.ResponseWriter.WriteHeader(200)
27 | this.Ctx.WriteString("You have successfully logged in.")
28 | }
29 |
30 | func (this *SessionController) Logout() {
31 | this.SetSession("authenticated", false)
32 | this.Ctx.ResponseWriter.WriteHeader(200)
33 | this.Ctx.WriteString("You have successfully logged out.")
34 | }
35 |
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/filters/firstfilter.go:
--------------------------------------------------------------------------------
1 | package filters
2 |
3 | import (
4 | "fmt"
5 | "time"
6 |
7 | "github.com/astaxie/beego/context"
8 | )
9 |
10 | var LogManager = func(ctx *context.Context) {
11 | fmt.Println("IP :: " + ctx.Request.RemoteAddr + ", Time :: " + time.Now().Format(time.RFC850))
12 | }
13 |
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | _ "my-first-beego-project/routers"
5 |
6 | "my-first-beego-project/controllers"
7 |
8 | "github.com/astaxie/beego"
9 | _ "github.com/astaxie/beego/session/redis"
10 | )
11 |
12 | func main() {
13 | beego.ErrorController(&controllers.ErrorController{})
14 | beego.BConfig.WebConfig.DirectoryIndex = true
15 | beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
16 | beego.Run()
17 | }
18 |
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/my-first-beego-project:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Go-Web-Development-Cookbook/36a67e571d00c191d12e7a1812dbcb76ce05513f/chapter08/my-first-beego-project/my-first-beego-project
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/routers/router.go:
--------------------------------------------------------------------------------
1 | // @APIVersion 1.0.0
2 | // @Title mobile API
3 | // @Description mobile has every tool to get any job done, so codename for the new mobile APIs.
4 | // @Contact astaxie@gmail.com
5 | package routers
6 |
7 | import (
8 | "my-first-beego-project/controllers"
9 | "my-first-beego-project/filters"
10 |
11 | "github.com/astaxie/beego"
12 | )
13 |
14 | func init() {
15 | beego.Router("/", &controllers.MainController{})
16 | beego.Router("/employees", &controllers.FirstController{}, "get:GetEmployees")
17 | beego.Router("/dashboard", &controllers.FirstController{}, "get:Dashbaord")
18 | beego.Router("/home", &controllers.SessionController{}, "get:Home")
19 | beego.Router("/login", &controllers.SessionController{}, "get:Login")
20 | beego.Router("/logout", &controllers.SessionController{}, "get:Logout")
21 | beego.InsertFilter("/*", beego.BeforeRouter, filters.LogManager)
22 | beego.Router("/employee", &controllers.FirstController{}, "get:GetEmployee")
23 |
24 | beego.Router("/getFromCache", &controllers.CacheController{}, "get:GetFromCache")
25 | }
26 |
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/static/js/reload.min.js:
--------------------------------------------------------------------------------
1 | function b(a){var c=new WebSocket(a);c.onclose=function(){setTimeout(function(){b(a)},2E3)};c.onmessage=function(){location.reload()}}try{if(window.WebSocket)try{b("ws://localhost:12450/reload")}catch(a){console.error(a)}else console.log("Your browser does not support WebSockets.")}catch(a){console.error("Exception during connecting to Reload:",a)};
2 |
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/swagger/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Go-Web-Development-Cookbook/36a67e571d00c191d12e7a1812dbcb76ce05513f/chapter08/my-first-beego-project/swagger/favicon-16x16.png
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/swagger/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Go-Web-Development-Cookbook/36a67e571d00c191d12e7a1812dbcb76ce05513f/chapter08/my-first-beego-project/swagger/favicon-32x32.png
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/swagger/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Swagger UI
7 |
8 |
9 |
10 |
11 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/swagger/oauth2-redirect.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
54 |
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/swagger/swagger-ui-bundle.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;AAu/FA;AA6+FA;;;;;;;;;;;;;;;;;;;;;;;;;;AAyTA;;;;;;AAoIA;AAi7FA;AAmtCA;AAi0IA;AA0oJA;AAgwFA;AAyrGA;AA0lFA;AA4nFA;AA+9CA;AA+gDA;AAwrCA;AA60EA;;;;;AA6oCA;AAsyJA;;;;;;;;;;;;;;AA64EA;AA4mIA;AAquJA;AA2qHA;AA2mGA;AAiiEA;AAq4DA;AAg3DA;AAoPA;;;;;;AAk7FA;AA07FA;;;;;AAi8CA;AAgsFA;AAs2CA;AAglCA;AAu9CA;AAy8EA;AAsiCA;AA+yFA;;;;;;;;;AAgkDA;AA2zIA;AAu7FA;AAmrFA;AAu0EA","sourceRoot":""}
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/swagger/swagger-ui-standalone-preset.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"swagger-ui-standalone-preset.js","sources":["webpack:///swagger-ui-standalone-preset.js"],"mappings":"AAAA;;;;;AA8QA;AAmvGA;AAuxFA;;;;;;AAocA;AAkvFA;AAu+CA;AAo+CA;AAgrCA;AAuyEA","sourceRoot":""}
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/swagger/swagger-ui.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";.swagger-ui html{box-sizing:border-box}.swagger-ui *,.swagger-ui :after,.swagger-ui :before{box-sizing:inherit}.swagger-ui body{margin:0;background:#fafafa}.swagger-ui .wrapper{width:100%;max-width:1460px;margin:0 auto;padding:0 20px}.swagger-ui .opblock-tag-section{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.swagger-ui .opblock-tag{display:-webkit-box;display:-ms-flexbox;display:flex;padding:10px 20px 10px 10px;cursor:pointer;transition:all .2s;border-bottom:1px solid rgba(59,65,81,.3);-webkit-box-align:center;-ms-flex-align:center;align-items:center}.swagger-ui .opblock-tag:hover{background:rgba(0,0,0,.02)}.swagger-ui .opblock-tag{font-size:24px;margin:0 0 5px;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .opblock-tag.no-desc span{-webkit-box-flex:1;-ms-flex:1;flex:1}.swagger-ui .opblock-tag svg{transition:all .4s}.swagger-ui .opblock-tag small{font-size:14px;font-weight:400;padding:0 10px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .parаmeter__type{font-size:12px;padding:5px 0;font-family:Source Code Pro,monospace;font-weight:600;color:#3b4151}.swagger-ui .view-line-link{position:relative;top:3px;width:20px;margin:0 5px;cursor:pointer;transition:all .5s}.swagger-ui .opblock{margin:0 0 15px;border:1px solid #000;border-radius:4px;box-shadow:0 0 3px rgba(0,0,0,.19)}.swagger-ui .opblock.is-open .opblock-summary{border-bottom:1px solid #000}.swagger-ui .opblock .opblock-section-header{padding:8px 20px;background:hsla(0,0%,100%,.8);box-shadow:0 1px 2px rgba(0,0,0,.1)}.swagger-ui .opblock .opblock-section-header,.swagger-ui .opblock .opblock-section-header label{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.swagger-ui .opblock .opblock-section-header label{font-size:12px;font-weight:700;margin:0;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .opblock .opblock-section-header label span{padding:0 10px 0 0}.swagger-ui .opblock .opblock-section-header h4{font-size:14px;margin:0;-webkit-box-flex:1;-ms-flex:1;flex:1;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .opblock .opblock-summary-method{font-size:14px;font-weight:700;min-width:80px;padding:6px 15px;text-align:center;border-radius:3px;background:#000;text-shadow:0 1px 0 rgba(0,0,0,.1);font-family:Titillium Web,sans-serif;color:#fff}.swagger-ui .opblock .opblock-summary-path,.swagger-ui .opblock .opblock-summary-path__deprecated{font-size:16px;display:-webkit-box;display:-ms-flexbox;display:flex;padding:0 10px;font-family:Source Code Pro,monospace;font-weight:600;color:#3b4151;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.swagger-ui .opblock .opblock-summary-path .view-line-link,.swagger-ui .opblock .opblock-summary-path__deprecated .view-line-link{position:relative;top:2px;width:0;margin:0;cursor:pointer;transition:all .5s}.swagger-ui .opblock .opblock-summary-path:hover .view-line-link,.swagger-ui .opblock .opblock-summary-path__deprecated:hover .view-line-link{width:18px;margin:0 5px}.swagger-ui .opblock .opblock-summary-path__deprecated{text-decoration:line-through}.swagger-ui .opblock .opblock-summary-description{font-size:13px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .opblock .opblock-summary{display:-webkit-box;display:-ms-flexbox;display:flex;padding:5px;cursor:pointer;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.swagger-ui .opblock.opblock-post{border-color:#49cc90;background:rgba(73,204,144,.1)}.swagger-ui .opblock.opblock-post .opblock-summary-method{background:#49cc90}.swagger-ui .opblock.opblock-post .opblock-summary{border-color:#49cc90}.swagger-ui .opblock.opblock-put{border-color:#fca130;background:rgba(252,161,48,.1)}.swagger-ui .opblock.opblock-put .opblock-summary-method{background:#fca130}.swagger-ui .opblock.opblock-put .opblock-summary{border-color:#fca130}.swagger-ui .opblock.opblock-delete{border-color:#f93e3e;background:rgba(249,62,62,.1)}.swagger-ui .opblock.opblock-delete .opblock-summary-method{background:#f93e3e}.swagger-ui .opblock.opblock-delete .opblock-summary{border-color:#f93e3e}.swagger-ui .opblock.opblock-get{border-color:#61affe;background:rgba(97,175,254,.1)}.swagger-ui .opblock.opblock-get .opblock-summary-method{background:#61affe}.swagger-ui .opblock.opblock-get .opblock-summary{border-color:#61affe}.swagger-ui .opblock.opblock-patch{border-color:#50e3c2;background:rgba(80,227,194,.1)}.swagger-ui .opblock.opblock-patch .opblock-summary-method{background:#50e3c2}.swagger-ui .opblock.opblock-patch .opblock-summary{border-color:#50e3c2}.swagger-ui .opblock.opblock-head{border-color:#9012fe;background:rgba(144,18,254,.1)}.swagger-ui .opblock.opblock-head .opblock-summary-method{background:#9012fe}.swagger-ui .opblock.opblock-head .opblock-summary{border-color:#9012fe}.swagger-ui .opblock.opblock-options{border-color:#0d5aa7;background:rgba(13,90,167,.1)}.swagger-ui .opblock.opblock-options .opblock-summary-method{background:#0d5aa7}.swagger-ui .opblock.opblock-options .opblock-summary{border-color:#0d5aa7}.swagger-ui .opblock.opblock-deprecated{opacity:.6;border-color:#ebebeb;background:hsla(0,0%,92%,.1)}.swagger-ui .opblock.opblock-deprecated .opblock-summary-method{background:#ebebeb}.swagger-ui .opblock.opblock-deprecated .opblock-summary{border-color:#ebebeb}.swagger-ui .opblock .opblock-schemes{padding:8px 20px}.swagger-ui .opblock .opblock-schemes .schemes-title{padding:0 10px 0 0}.swagger-ui .tab{display:-webkit-box;display:-ms-flexbox;display:flex;margin:20px 0 10px;padding:0;list-style:none}.swagger-ui .tab li{font-size:12px;min-width:100px;min-width:90px;padding:0;cursor:pointer;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .tab li:first-of-type{position:relative;padding-left:0}.swagger-ui .tab li:first-of-type:after{position:absolute;top:0;right:6px;width:1px;height:100%;content:"";background:rgba(0,0,0,.2)}.swagger-ui .tab li.active{font-weight:700}.swagger-ui .opblock-description-wrapper,.swagger-ui .opblock-title_normal{padding:15px 20px}.swagger-ui .opblock-description-wrapper,.swagger-ui .opblock-description-wrapper h4,.swagger-ui .opblock-title_normal,.swagger-ui .opblock-title_normal h4{font-size:12px;margin:0 0 5px;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .opblock-description-wrapper p,.swagger-ui .opblock-title_normal p{font-size:14px;margin:0;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .execute-wrapper{padding:20px;text-align:right}.swagger-ui .execute-wrapper .btn{width:100%;padding:8px 40px}.swagger-ui .body-param-options{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.swagger-ui .body-param-options .body-param-edit{padding:10px 0}.swagger-ui .body-param-options label{padding:8px 0}.swagger-ui .body-param-options label select{margin:3px 0 0}.swagger-ui .responses-inner{padding:20px}.swagger-ui .responses-inner h4,.swagger-ui .responses-inner h5{font-size:12px;margin:10px 0 5px;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .response-col_status{font-size:14px;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .response-col_status .response-undocumented{font-size:11px;font-family:Source Code Pro,monospace;font-weight:600;color:#999}.swagger-ui .response-col_description__inner span{font-size:12px;font-style:italic;display:block;margin:10px 0;padding:10px;border-radius:4px;background:#41444e;font-family:Source Code Pro,monospace;font-weight:600;color:#fff}.swagger-ui .response-col_description__inner span p{margin:0}.swagger-ui .opblock-body pre{font-size:12px;margin:0;padding:10px;word-wrap:break-word;word-break:break-all;word-break:break-word;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto;white-space:pre-wrap;border-radius:4px;background:#41444e;overflow-wrap:break-word;font-family:Source Code Pro,monospace;font-weight:600;color:#fff}.swagger-ui .opblock-body pre span{color:#fff!important}.swagger-ui .opblock-body pre .headerline{display:block}.swagger-ui .scheme-container{margin:0 0 20px;padding:30px 0;background:#fff;box-shadow:0 1px 2px 0 rgba(0,0,0,.15)}.swagger-ui .scheme-container .schemes{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.swagger-ui .scheme-container .schemes>label{font-size:12px;font-weight:700;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin:-20px 15px 0 0;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .scheme-container .schemes>label select{min-width:130px;text-transform:uppercase}.swagger-ui .loading-container{padding:40px 0 60px}.swagger-ui .loading-container .loading{position:relative}.swagger-ui .loading-container .loading:after{font-size:10px;font-weight:700;position:absolute;top:50%;left:50%;content:"loading";-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);text-transform:uppercase;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .loading-container .loading:before{position:absolute;top:50%;left:50%;display:block;width:60px;height:60px;margin:-30px;content:"";-webkit-animation:rotation 1s infinite linear,opacity .5s;animation:rotation 1s infinite linear,opacity .5s;opacity:1;border:2px solid rgba(85,85,85,.1);border-top-color:rgba(0,0,0,.6);border-radius:100%;-webkit-backface-visibility:hidden;backface-visibility:hidden}@-webkit-keyframes rotation{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes rotation{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@-webkit-keyframes blinker{50%{opacity:0}}@keyframes blinker{50%{opacity:0}}.swagger-ui .btn{font-size:14px;font-weight:700;padding:5px 23px;transition:all .3s;border:2px solid #888;border-radius:4px;background:transparent;box-shadow:0 1px 2px rgba(0,0,0,.1);font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .btn[disabled]{cursor:not-allowed;opacity:.3}.swagger-ui .btn:hover{box-shadow:0 0 5px rgba(0,0,0,.3)}.swagger-ui .btn.cancel{border-color:#ff6060;font-family:Titillium Web,sans-serif;color:#ff6060}.swagger-ui .btn.authorize{line-height:1;display:inline;color:#49cc90;border-color:#49cc90}.swagger-ui .btn.authorize span{float:left;padding:4px 20px 0 0}.swagger-ui .btn.authorize svg{fill:#49cc90}.swagger-ui .btn.execute{-webkit-animation:pulse 2s infinite;animation:pulse 2s infinite;color:#fff;border-color:#4990e2}@-webkit-keyframes pulse{0%{color:#fff;background:#4990e2;box-shadow:0 0 0 0 rgba(73,144,226,.8)}70%{box-shadow:0 0 0 5px rgba(73,144,226,0)}to{color:#fff;background:#4990e2;box-shadow:0 0 0 0 rgba(73,144,226,0)}}@keyframes pulse{0%{color:#fff;background:#4990e2;box-shadow:0 0 0 0 rgba(73,144,226,.8)}70%{box-shadow:0 0 0 5px rgba(73,144,226,0)}to{color:#fff;background:#4990e2;box-shadow:0 0 0 0 rgba(73,144,226,0)}}.swagger-ui .btn-group{display:-webkit-box;display:-ms-flexbox;display:flex;padding:30px}.swagger-ui .btn-group .btn{-webkit-box-flex:1;-ms-flex:1;flex:1}.swagger-ui .btn-group .btn:first-child{border-radius:4px 0 0 4px}.swagger-ui .btn-group .btn:last-child{border-radius:0 4px 4px 0}.swagger-ui .authorization__btn{padding:0 10px;border:none;background:none}.swagger-ui .authorization__btn.locked{opacity:1}.swagger-ui .authorization__btn.unlocked{opacity:.4}.swagger-ui .expand-methods,.swagger-ui .expand-operation{border:none;background:none}.swagger-ui .expand-methods svg,.swagger-ui .expand-operation svg{width:20px;height:20px}.swagger-ui .expand-methods{padding:0 10px}.swagger-ui .expand-methods:hover svg{fill:#444}.swagger-ui .expand-methods svg{transition:all .3s;fill:#777}.swagger-ui button{cursor:pointer;outline:none}.swagger-ui select{font-size:14px;font-weight:700;padding:5px 40px 5px 10px;border:2px solid #41444e;border-radius:4px;background:#f7f7f7 url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMCAyMCI+ICAgIDxwYXRoIGQ9Ik0xMy40MTggNy44NTljLjI3MS0uMjY4LjcwOS0uMjY4Ljk3OCAwIC4yNy4yNjguMjcyLjcwMSAwIC45NjlsLTMuOTA4IDMuODNjLS4yNy4yNjgtLjcwNy4yNjgtLjk3OSAwbC0zLjkwOC0zLjgzYy0uMjctLjI2Ny0uMjctLjcwMSAwLS45NjkuMjcxLS4yNjguNzA5LS4yNjguOTc4IDBMMTAgMTFsMy40MTgtMy4xNDF6Ii8+PC9zdmc+) right 10px center no-repeat;background-size:20px;box-shadow:0 1px 2px 0 rgba(0,0,0,.25);font-family:Titillium Web,sans-serif;color:#3b4151;-webkit-appearance:none;-moz-appearance:none;appearance:none}.swagger-ui select[multiple]{margin:5px 0;padding:5px;background:#f7f7f7}.swagger-ui .opblock-body select{min-width:230px}.swagger-ui label{font-size:12px;font-weight:700;margin:0 0 5px;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui input[type=email],.swagger-ui input[type=password],.swagger-ui input[type=search],.swagger-ui input[type=text]{min-width:100px;margin:5px 0;padding:8px 10px;border:1px solid #d9d9d9;border-radius:4px;background:#fff}.swagger-ui input[type=email].invalid,.swagger-ui input[type=password].invalid,.swagger-ui input[type=search].invalid,.swagger-ui input[type=text].invalid{-webkit-animation:shake .4s 1;animation:shake .4s 1;border-color:#f93e3e;background:#feebeb}@-webkit-keyframes shake{10%,90%{-webkit-transform:translate3d(-1px,0,0);transform:translate3d(-1px,0,0)}20%,80%{-webkit-transform:translate3d(2px,0,0);transform:translate3d(2px,0,0)}30%,50%,70%{-webkit-transform:translate3d(-4px,0,0);transform:translate3d(-4px,0,0)}40%,60%{-webkit-transform:translate3d(4px,0,0);transform:translate3d(4px,0,0)}}@keyframes shake{10%,90%{-webkit-transform:translate3d(-1px,0,0);transform:translate3d(-1px,0,0)}20%,80%{-webkit-transform:translate3d(2px,0,0);transform:translate3d(2px,0,0)}30%,50%,70%{-webkit-transform:translate3d(-4px,0,0);transform:translate3d(-4px,0,0)}40%,60%{-webkit-transform:translate3d(4px,0,0);transform:translate3d(4px,0,0)}}.swagger-ui textarea{font-size:12px;width:100%;min-height:280px;padding:10px;border:none;border-radius:4px;outline:none;background:hsla(0,0%,100%,.8);font-family:Source Code Pro,monospace;font-weight:600;color:#3b4151}.swagger-ui textarea:focus{border:2px solid #61affe}.swagger-ui textarea.curl{font-size:12px;min-height:100px;margin:0;padding:10px;resize:none;border-radius:4px;background:#41444e;font-family:Source Code Pro,monospace;font-weight:600;color:#fff}.swagger-ui .checkbox{padding:5px 0 10px;transition:opacity .5s;color:#333}.swagger-ui .checkbox label{display:-webkit-box;display:-ms-flexbox;display:flex}.swagger-ui .checkbox p{font-weight:400!important;font-style:italic;margin:0!important;font-family:Source Code Pro,monospace;font-weight:600;color:#3b4151}.swagger-ui .checkbox input[type=checkbox]{display:none}.swagger-ui .checkbox input[type=checkbox]+label>.item{position:relative;top:3px;display:inline-block;width:16px;height:16px;margin:0 8px 0 0;padding:5px;cursor:pointer;border-radius:1px;background:#e8e8e8;box-shadow:0 0 0 2px #e8e8e8;-webkit-box-flex:0;-ms-flex:none;flex:none}.swagger-ui .checkbox input[type=checkbox]+label>.item:active{-webkit-transform:scale(.9);transform:scale(.9)}.swagger-ui .checkbox input[type=checkbox]:checked+label>.item{background:#e8e8e8 url("data:image/svg+xml;charset=utf-8,%3Csvg width='10' height='8' viewBox='3 7 10 8' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%2341474E' fill-rule='evenodd' d='M6.333 15L3 11.667l1.333-1.334 2 2L11.667 7 13 8.333z'/%3E%3C/svg%3E") 50% no-repeat}.swagger-ui .dialog-ux{position:fixed;z-index:9999;top:0;right:0;bottom:0;left:0}.swagger-ui .dialog-ux .backdrop-ux{position:fixed;top:0;right:0;bottom:0;left:0;background:rgba(0,0,0,.8)}.swagger-ui .dialog-ux .modal-ux{position:absolute;z-index:9999;top:50%;left:50%;width:100%;min-width:300px;max-width:650px;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);border:1px solid #ebebeb;border-radius:4px;background:#fff;box-shadow:0 10px 30px 0 rgba(0,0,0,.2)}.swagger-ui .dialog-ux .modal-ux-content{overflow-y:auto;max-height:540px;padding:20px}.swagger-ui .dialog-ux .modal-ux-content p{font-size:12px;margin:0 0 5px;color:#41444e;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .dialog-ux .modal-ux-content h4{font-size:18px;font-weight:600;margin:15px 0 0;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .dialog-ux .modal-ux-header{display:-webkit-box;display:-ms-flexbox;display:flex;padding:12px 0;border-bottom:1px solid #ebebeb;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.swagger-ui .dialog-ux .modal-ux-header .close-modal{padding:0 10px;border:none;background:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}.swagger-ui .dialog-ux .modal-ux-header h3{font-size:20px;font-weight:600;margin:0;padding:0 20px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .model{font-size:12px;font-weight:300;font-family:Source Code Pro,monospace;font-weight:600;color:#3b4151}.swagger-ui .model-toggle{font-size:10px;position:relative;top:6px;display:inline-block;margin:auto .3em;cursor:pointer;transition:-webkit-transform .15s ease-in;transition:transform .15s ease-in;transition:transform .15s ease-in,-webkit-transform .15s ease-in;-webkit-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:50% 50%;transform-origin:50% 50%}.swagger-ui .model-toggle.collapsed{-webkit-transform:rotate(0deg);transform:rotate(0deg)}.swagger-ui .model-toggle:after{display:block;width:20px;height:20px;content:"";background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z'/%3E%3C/svg%3E") 50% no-repeat;background-size:100%}.swagger-ui .model-jump-to-path{position:relative;cursor:pointer}.swagger-ui .model-jump-to-path .view-line-link{position:absolute;top:-.4em;cursor:pointer}.swagger-ui .model-title{position:relative}.swagger-ui .model-title:hover .model-hint{visibility:visible}.swagger-ui .model-hint{position:absolute;top:-1.8em;visibility:hidden;padding:.1em .5em;white-space:nowrap;color:#ebebeb;border-radius:4px;background:rgba(0,0,0,.7)}.swagger-ui section.models{margin:30px 0;border:1px solid rgba(59,65,81,.3);border-radius:4px}.swagger-ui section.models.is-open{padding:0 0 20px}.swagger-ui section.models.is-open h4{margin:0 0 5px;border-bottom:1px solid rgba(59,65,81,.3)}.swagger-ui section.models.is-open h4 svg{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.swagger-ui section.models h4{font-size:16px;display:-webkit-box;display:-ms-flexbox;display:flex;margin:0;padding:10px 20px 10px 10px;cursor:pointer;transition:all .2s;font-family:Titillium Web,sans-serif;color:#777;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.swagger-ui section.models h4 svg{transition:all .4s}.swagger-ui section.models h4 span{-webkit-box-flex:1;-ms-flex:1;flex:1}.swagger-ui section.models h4:hover{background:rgba(0,0,0,.02)}.swagger-ui section.models h5{font-size:16px;margin:0 0 10px;font-family:Titillium Web,sans-serif;color:#777}.swagger-ui section.models .model-jump-to-path{position:relative;top:5px}.swagger-ui section.models .model-container{margin:0 20px 15px;transition:all .5s;border-radius:4px;background:rgba(0,0,0,.05)}.swagger-ui section.models .model-container:hover{background:rgba(0,0,0,.07)}.swagger-ui section.models .model-container:first-of-type{margin:20px}.swagger-ui section.models .model-container:last-of-type{margin:0 20px}.swagger-ui section.models .model-box{background:none}.swagger-ui .model-box{padding:10px;border-radius:4px;background:rgba(0,0,0,.1)}.swagger-ui .model-box .model-jump-to-path{position:relative;top:4px}.swagger-ui .model-title{font-size:16px;font-family:Titillium Web,sans-serif;color:#555}.swagger-ui span>span.model,.swagger-ui span>span.model .brace-close{padding:0 0 0 10px}.swagger-ui .prop-type{color:#55a}.swagger-ui .prop-enum{display:block}.swagger-ui .prop-format{color:#999}.swagger-ui table{width:100%;padding:0 10px;border-collapse:collapse}.swagger-ui table.model tbody tr td{padding:0;vertical-align:top}.swagger-ui table.model tbody tr td:first-of-type{width:100px;padding:0}.swagger-ui table.headers td{font-size:12px;font-weight:300;vertical-align:middle;font-family:Source Code Pro,monospace;font-weight:600;color:#3b4151}.swagger-ui table tbody tr td{padding:10px 0 0;vertical-align:top}.swagger-ui table tbody tr td:first-of-type{width:20%;padding:10px 0}.swagger-ui table thead tr td,.swagger-ui table thead tr th{font-size:12px;font-weight:700;padding:12px 0;text-align:left;border-bottom:1px solid rgba(59,65,81,.2);font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .parameters-col_description p{font-size:14px;margin:0;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .parameters-col_description input[type=text]{width:100%;max-width:340px}.swagger-ui .parameter__name{font-size:16px;font-weight:400;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .parameter__name.required{font-weight:700}.swagger-ui .parameter__name.required:after{font-size:10px;position:relative;top:-6px;padding:5px;content:"required";color:rgba(255,0,0,.6)}.swagger-ui .parameter__in{font-size:12px;font-style:italic;font-family:Source Code Pro,monospace;font-weight:600;color:#888}.swagger-ui .table-container{padding:20px}.swagger-ui .topbar{padding:8px 30px;background-color:#89bf04}.swagger-ui .topbar .topbar-wrapper{-ms-flex-align:center}.swagger-ui .topbar .topbar-wrapper,.swagger-ui .topbar a{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;align-items:center}.swagger-ui .topbar a{font-size:1.5em;font-weight:700;max-width:300px;text-decoration:none;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-align:center;font-family:Titillium Web,sans-serif;color:#fff}.swagger-ui .topbar a span{margin:0;padding:0 10px}.swagger-ui .topbar .download-url-wrapper{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:3;-ms-flex:3;flex:3}.swagger-ui .topbar .download-url-wrapper input[type=text]{width:100%;min-width:350px;margin:0;border:2px solid #547f00;border-radius:4px 0 0 4px;outline:none}.swagger-ui .topbar .download-url-wrapper .download-url-button{font-size:16px;font-weight:700;padding:4px 40px;border:none;border-radius:0 4px 4px 0;background:#547f00;font-family:Titillium Web,sans-serif;color:#fff}.swagger-ui .info{margin:50px 0}.swagger-ui .info hgroup.main{margin:0 0 20px}.swagger-ui .info hgroup.main a{font-size:12px}.swagger-ui .info li,.swagger-ui .info p,.swagger-ui .info table{font-size:14px;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .info h1,.swagger-ui .info h2,.swagger-ui .info h3,.swagger-ui .info h4,.swagger-ui .info h5{font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .info code{padding:3px 5px;border-radius:4px;background:rgba(0,0,0,.05);font-family:Source Code Pro,monospace;font-weight:600;color:#9012fe}.swagger-ui .info a{font-size:14px;transition:all .4s;font-family:Open Sans,sans-serif;color:#4990e2}.swagger-ui .info a:hover{color:#1f69c0}.swagger-ui .info>div{margin:0 0 5px}.swagger-ui .info .base-url{font-size:12px;font-weight:300!important;margin:0;font-family:Source Code Pro,monospace;font-weight:600;color:#3b4151}.swagger-ui .info .title{font-size:36px;margin:0;font-family:Open Sans,sans-serif;color:#3b4151}.swagger-ui .info .title small{font-size:10px;position:relative;top:-5px;display:inline-block;margin:0 0 0 5px;padding:2px 4px;vertical-align:super;border-radius:57px;background:#7d8492}.swagger-ui .info .title small pre{margin:0;font-family:Titillium Web,sans-serif;color:#fff}.swagger-ui .auth-btn-wrapper{display:-webkit-box;display:-ms-flexbox;display:flex;padding:10px 0;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.swagger-ui .auth-wrapper{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1;flex:1;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.swagger-ui .auth-wrapper .authorize{padding-right:20px}.swagger-ui .auth-container{margin:0 0 10px;padding:10px 20px;border-bottom:1px solid #ebebeb}.swagger-ui .auth-container:last-of-type{margin:0;padding:10px 20px;border:0}.swagger-ui .auth-container h4{margin:5px 0 15px!important}.swagger-ui .auth-container .wrapper{margin:0;padding:0}.swagger-ui .auth-container input[type=password],.swagger-ui .auth-container input[type=text]{min-width:230px}.swagger-ui .auth-container .errors{font-size:12px;padding:10px;border-radius:4px;font-family:Source Code Pro,monospace;font-weight:600;color:#3b4151}.swagger-ui .scopes h2{font-size:14px;font-family:Titillium Web,sans-serif;color:#3b4151}.swagger-ui .scope-def{padding:0 0 20px}.swagger-ui .errors-wrapper{margin:20px;padding:10px 20px;-webkit-animation:scaleUp .5s;animation:scaleUp .5s;border:2px solid #f93e3e;border-radius:4px;background:rgba(249,62,62,.1)}.swagger-ui .errors-wrapper .error-wrapper{margin:0 0 10px}.swagger-ui .errors-wrapper .errors h4{font-size:14px;margin:0;font-family:Source Code Pro,monospace;font-weight:600;color:#3b4151}.swagger-ui .errors-wrapper .errors small{color:#666}.swagger-ui .errors-wrapper hgroup{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.swagger-ui .errors-wrapper hgroup h4{font-size:20px;margin:0;-webkit-box-flex:1;-ms-flex:1;flex:1;font-family:Titillium Web,sans-serif;color:#3b4151}@-webkit-keyframes scaleUp{0%{-webkit-transform:scale(.8);transform:scale(.8);opacity:0}to{-webkit-transform:scale(1);transform:scale(1);opacity:1}}@keyframes scaleUp{0%{-webkit-transform:scale(.8);transform:scale(.8);opacity:0}to{-webkit-transform:scale(1);transform:scale(1);opacity:1}}.swagger-ui .Resizer.vertical.disabled{display:none}
2 | /*# sourceMappingURL=swagger-ui.css.map*/
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/swagger/swagger-ui.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"swagger-ui.css","sources":[],"mappings":"","sourceRoot":""}
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/swagger/swagger-ui.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AA0yCA;AAoyHA;AAmyHA;AAykGA;AA+9BA;AA6iCA;AAojCA;AAu5BA","sourceRoot":""}
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/swagger/swagger.json:
--------------------------------------------------------------------------------
1 | {
2 | "swagger": "2.0",
3 | "info": {
4 | "title": "mobile API",
5 | "description": "mobile has every tool to get any job done, so codename for the new mobile APIs.",
6 | "version": "1.0.0",
7 | "contact": {
8 | "email": "astaxie@gmail.com"
9 | }
10 | },
11 | "paths": null,
12 | "definitions": {
13 | ".CmsResponse": {
14 | "type": "object"
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/swagger/swagger.yml:
--------------------------------------------------------------------------------
1 | swagger: "2.0"
2 | info:
3 | title: mobile API
4 | description: mobile has every tool to get any job done, so codename for the new
5 | mobile APIs.
6 | version: 1.0.0
7 | contact:
8 | email: astaxie@gmail.com
9 | paths: {}
10 | definitions:
11 | .CmsResponse:
12 | type: object
13 |
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/tests/default_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "net/http"
5 | "net/http/httptest"
6 | "testing"
7 | "runtime"
8 | "path/filepath"
9 | _ "my-first-beego-project/routers"
10 |
11 | "github.com/astaxie/beego"
12 | . "github.com/smartystreets/goconvey/convey"
13 | )
14 |
15 | func init() {
16 | _, file, _, _ := runtime.Caller(1)
17 | apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".." + string(filepath.Separator))))
18 | beego.TestBeegoInit(apppath)
19 | }
20 |
21 |
22 | // TestBeego is a sample to run an endpoint test
23 | func TestBeego(t *testing.T) {
24 | r, _ := http.NewRequest("GET", "/", nil)
25 | w := httptest.NewRecorder()
26 | beego.BeeApp.Handlers.ServeHTTP(w, r)
27 |
28 | beego.Trace("testing", "TestBeego", "Code[%d]\n%s", w.Code, w.Body.String())
29 |
30 | Convey("Subject: Test Station Endpoint\n", t, func() {
31 | Convey("Status Code Should Be 200", func() {
32 | So(w.Code, ShouldEqual, 200)
33 | })
34 | Convey("The Result Should Not Be Empty", func() {
35 | So(w.Body.Len(), ShouldBeGreaterThan, 0)
36 | })
37 | })
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/views/404.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{.content}}
5 |
6 |
7 |
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/views/500.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{.content}}
5 |
6 |
7 |
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/views/dashboard.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{range .employees}}
6 |
7 | {{.Id}}
8 | {{.FirstName}}
9 | {{.LastName}}
10 |
11 | {{end}}
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/chapter08/my-first-beego-project/views/genericerror.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{.content}}
5 |
6 |
7 |
--------------------------------------------------------------------------------
/chapter08/nginx.conf:
--------------------------------------------------------------------------------
1 |
2 | #user nobody;
3 | worker_processes 1;
4 |
5 | #error_log logs/error.log;
6 | #error_log logs/error.log notice;
7 | #error_log logs/error.log info;
8 |
9 | #pid logs/nginx.pid;
10 |
11 |
12 | events {
13 | worker_connections 1024;
14 | }
15 |
16 |
17 | http {
18 | include mime.types;
19 | default_type application/octet-stream;
20 |
21 | #log_format main '$remote_addr - $remote_user [$time_local] "$request" '
22 | # '$status $body_bytes_sent "$http_referer" '
23 | # '"$http_user_agent" "$http_x_forwarded_for"';
24 |
25 | #access_log logs/access.log main;
26 |
27 | sendfile on;
28 | #tcp_nopush on;
29 |
30 | #keepalive_timeout 0;
31 | keepalive_timeout 65;
32 |
33 | #gzip on;
34 |
35 | server {
36 | listen 80;
37 | server_name localhost;
38 |
39 | #charset koi8-r;
40 |
41 | #access_log logs/host.access.log main;
42 |
43 | location / {
44 | # root html;
45 | # index index.html index.htm;
46 | proxy_pass http://localhost:8080/;
47 | }
48 |
49 | #error_page 404 /404.html;
50 |
51 | # redirect server error pages to the static page /50x.html
52 | #
53 | error_page 500 502 503 504 /50x.html;
54 | location = /50x.html {
55 | root html;
56 | }
57 |
58 | # proxy the PHP scripts to Apache listening on 127.0.0.1:80
59 | #
60 | #location ~ \.php$ {
61 | # proxy_pass http://127.0.0.1;
62 | #}
63 |
64 | # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
65 | #
66 | #location ~ \.php$ {
67 | # root html;
68 | # fastcgi_pass 127.0.0.1:9000;
69 | # fastcgi_index index.php;
70 | # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
71 | # include fastcgi_params;
72 | #}
73 |
74 | # deny access to .htaccess files, if Apache's document root
75 | # concurs with nginx's one
76 | #
77 | #location ~ /\.ht {
78 | # deny all;
79 | #}
80 | }
81 |
82 |
83 | # another virtual host using mix of IP-, name-, and port-based configuration
84 | #
85 | #server {
86 | # listen 8000;
87 | # listen somename:8080;
88 | # server_name somename alias another.alias;
89 |
90 | # location / {
91 | # root html;
92 | # index index.html index.htm;
93 | # }
94 | #}
95 |
96 |
97 | # HTTPS server
98 | #
99 | #server {
100 | # listen 443 ssl;
101 | # server_name localhost;
102 |
103 | # ssl_certificate cert.pem;
104 | # ssl_certificate_key cert.key;
105 |
106 | # ssl_session_cache shared:SSL:1m;
107 | # ssl_session_timeout 5m;
108 |
109 | # ssl_ciphers HIGH:!aNULL:!MD5;
110 | # ssl_prefer_server_ciphers on;
111 |
112 | # location / {
113 | # root html;
114 | # index index.html index.htm;
115 | # }
116 | #}
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/chapter09/build-go-docker-image/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.9.2
2 |
3 | ENV SRC_DIR=/go/src/github.com/arpitaggarwal/
4 | ENV GOBIN=/go/bin
5 |
6 | WORKDIR $GOBIN
7 |
8 | ADD . $SRC_DIR
9 |
10 | RUN cd /go/src/;
11 |
12 | RUN go install github.com/arpitaggarwal/;
13 | ENTRYPOINT ["./arpitaggarwal"]
14 |
15 | EXPOSE 8080
16 |
--------------------------------------------------------------------------------
/chapter09/build-go-docker-image/http-server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 | )
8 |
9 | const (
10 | CONN_PORT = "8080"
11 | )
12 |
13 | func helloWorld(w http.ResponseWriter, r *http.Request) {
14 | fmt.Fprintf(w, "Hello World!")
15 | }
16 |
17 | func main() {
18 | http.HandleFunc("/", helloWorld)
19 | err := http.ListenAndServe(":"+CONN_PORT, nil)
20 | if err != nil {
21 | log.Fatal("error starting http server : ", err)
22 | return
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/chapter09/build-go-webapp-docker-image/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.9.2
2 |
3 | ENV SRC_DIR=/go/src/github.com/arpitaggarwal/
4 | ENV GOBIN=/go/bin
5 |
6 | WORKDIR $GOBIN
7 |
8 | ADD . $SRC_DIR
9 |
10 | RUN cd /go/src/;
11 | RUN go get github.com/go-sql-driver/mysql;
12 | RUN go get github.com/gorilla/mux;
13 |
14 | RUN go install github.com/arpitaggarwal/;
15 | ENTRYPOINT ["./arpitaggarwal"]
16 |
17 | EXPOSE 8080
18 |
--------------------------------------------------------------------------------
/chapter09/build-go-webapp-docker-image/http-server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bytes"
5 | "database/sql"
6 | "fmt"
7 | "log"
8 | "net/http"
9 |
10 | _ "github.com/go-sql-driver/mysql"
11 | "github.com/gorilla/mux"
12 | )
13 |
14 | var db *sql.DB
15 | var connectionError error
16 |
17 | const (
18 | CONN_PORT = "8080"
19 | DRIVER_NAME = "mysql"
20 | DATA_SOURCE_NAME = "root:my-pass@tcp(mysql-container:3306)/mysql"
21 | )
22 |
23 | func init() {
24 | db, connectionError = sql.Open(DRIVER_NAME, DATA_SOURCE_NAME)
25 | if connectionError != nil {
26 | log.Fatal("error connecting to database : ", connectionError)
27 | }
28 | }
29 |
30 | func getDBInfo(w http.ResponseWriter, r *http.Request) {
31 | rows, err := db.Query("SELECT SUBSTRING_INDEX(USER(), '@', -1) AS ip, @@hostname as hostname, @@port as port, DATABASE() as current_database;")
32 | if err != nil {
33 | log.Print("error executing database query : ", err)
34 | return
35 | }
36 | var buffer bytes.Buffer
37 |
38 | for rows.Next() {
39 | var ip string
40 | var hostname string
41 | var port string
42 | var current_database string
43 | err = rows.Scan(&ip, &hostname, &port, ¤t_database)
44 | buffer.WriteString("IP :: " + ip + " | HostName :: " + hostname + " | Port :: " + port + " | Current Database :: " + current_database)
45 | }
46 |
47 | fmt.Fprintf(w, buffer.String())
48 | }
49 |
50 | func main() {
51 | router := mux.NewRouter()
52 | router.HandleFunc("/", getDBInfo).Methods("GET")
53 | defer db.Close()
54 | err := http.ListenAndServe(":"+CONN_PORT, router)
55 | if err != nil {
56 | log.Fatal("error starting http server : ", err)
57 | return
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/chapter10/.gitignore:
--------------------------------------------------------------------------------
1 | domain.crt
2 | domain.key
3 |
--------------------------------------------------------------------------------
/chapter10/certs/domain.csr:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE REQUEST-----
2 | MIICoTCCAYkCAQAwXDELMAkGA1UEBhMCSU4xDzANBgNVBAgTBk11bWJhaTEVMBMG
3 | A1UEBxMMQW5kaGVyaSBFYXN0MQ4wDAYDVQQKEwVQYWNrdDEVMBMGA1UEAxMMcGFj
4 | a3RwdWIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvyoeZUPq
5 | 6cYWF3LaB0LooyZFYxd8Ex1eMFcsf0jgwFPFDAAHctAlKQKZLREQmbd8qBal0CsU
6 | MxVJLY6NRGUvYrI4pkiBQPIKTZ+5f2T8X1b21542sVy26SZE+e6HRDIkGNc8X8Iw
7 | w2/2mwBDIv7N6+pPvCq5+W97ob8b3l3IbZtj1Y05sqfjHzFJAMcBmUZQ29wWpjHz
8 | qqxx4LqmswTMARo5Tps8tXFBBnck2xJ8ViOpeTl0/s4YL50TRVd2m1RUysmOB4vP
9 | Cdwp3rWpxwyHd+jUT+NCmvDjChmjcHEwGHEQ93pF9+Af3ZzDemnd0b0culIVYlwB
10 | kNukX+JeZ+ibzQIDAQABoAAwDQYJKoZIhvcNAQEFBQADggEBAGODuvDU/CIeydFP
11 | 71c9Ze952aIzAAXenAMXPabLjHY7r61TzkLj4Trh6fyWM1fqWju6U7a0FylESezk
12 | 6Isgzm5MAGVuRPsyLNE2Zh3DgxVCllXJVqE8l59AFV4LpvGYVjNq8vzyJi92mdf8
13 | cEXSm6qVotQLr+rZ/dTWSGM7pySAjDZ+DO1n5uRx9lNuCVRklzPzABkPrfRUWgMg
14 | dk9dWconbcMlWbKflKFIvgXjrDnGV08ImxFoDQbK+QimINSZK64YaKh/HrbwmxDW
15 | ZOd+5VpyYYRLENtqSfm7+77dp/t5q9Q9kcaNaW+DO/IruMFnNx0CVdxLO7rsBpk9
16 | +pe7XDE=
17 | -----END CERTIFICATE REQUEST-----
18 |
--------------------------------------------------------------------------------
/chapter10/create-jwt.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "log"
6 | "net/http"
7 | "os"
8 | "time"
9 |
10 | jwt "github.com/dgrijalva/jwt-go"
11 | "github.com/gorilla/handlers"
12 | "github.com/gorilla/mux"
13 | )
14 |
15 | const (
16 | CONN_HOST = "localhost"
17 | CONN_PORT = "8080"
18 | CLAIM_ISSUER = "Packt"
19 | CLAIM_EXPIRY_IN_HOURS = 24
20 | )
21 |
22 | type Employee struct {
23 | Id int `json:"id"`
24 | FirstName string `json:"firstName"`
25 | LastName string `json:"lastName"`
26 | }
27 |
28 | type Employees []Employee
29 |
30 | var employees []Employee
31 |
32 | func init() {
33 | employees = Employees{
34 | Employee{Id: 1, FirstName: "Foo", LastName: "Bar"},
35 | Employee{Id: 2, FirstName: "Baz", LastName: "Qux"},
36 | }
37 | }
38 |
39 | var signature = []byte("secret")
40 |
41 | func getToken(w http.ResponseWriter, r *http.Request) {
42 | claims := &jwt.StandardClaims{
43 | ExpiresAt: time.Now().Add(time.Hour * CLAIM_EXPIRY_IN_HOURS).Unix(),
44 | Issuer: CLAIM_ISSUER,
45 | }
46 | token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
47 | tokenString, _ := token.SignedString(signature)
48 | w.Write([]byte(tokenString))
49 | }
50 |
51 | func getStatus(w http.ResponseWriter, r *http.Request) {
52 | w.Write([]byte("API is up and running"))
53 | }
54 |
55 | func getEmployees(w http.ResponseWriter, r *http.Request) {
56 | json.NewEncoder(w).Encode(employees)
57 | }
58 |
59 | func main() {
60 | muxRouter := mux.NewRouter().StrictSlash(true)
61 | muxRouter.HandleFunc("/status", getStatus).Methods("GET")
62 | muxRouter.HandleFunc("/get-token", getToken).Methods("GET")
63 | muxRouter.HandleFunc("/employees", getEmployees).Methods("GET")
64 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, handlers.LoggingHandler(os.Stdout, muxRouter))
65 | if err != nil {
66 | log.Fatal("error starting http server : ", err)
67 | return
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/chapter10/http-jwt.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "log"
6 | "net/http"
7 | "os"
8 | "time"
9 |
10 | jwtmiddleware "github.com/auth0/go-jwt-middleware"
11 | jwt "github.com/dgrijalva/jwt-go"
12 | "github.com/gorilla/handlers"
13 | "github.com/gorilla/mux"
14 | )
15 |
16 | const (
17 | CONN_HOST = "localhost"
18 | CONN_PORT = "8080"
19 | )
20 |
21 | type Employee struct {
22 | Id int `json:"id"`
23 | FirstName string `json:"firstName"`
24 | LastName string `json:"lastName"`
25 | }
26 |
27 | type Employees []Employee
28 |
29 | var employees []Employee
30 |
31 | func init() {
32 | employees = Employees{
33 | Employee{Id: 1, FirstName: "Foo", LastName: "Bar"},
34 | Employee{Id: 2, FirstName: "Baz", LastName: "Qux"},
35 | }
36 | }
37 |
38 | func notImplemented(w http.ResponseWriter, r *http.Request) {
39 | w.Write([]byte("Not Implemented"))
40 | }
41 |
42 | var mySigningKey = []byte("secret")
43 |
44 | var jwtMiddleware = jwtmiddleware.New(jwtmiddleware.Options{
45 | ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
46 | return mySigningKey, nil
47 | },
48 | SigningMethod: jwt.SigningMethodHS256,
49 | })
50 |
51 | type Product struct {
52 | Id int
53 | Name string
54 | Slug string
55 | Description string
56 | }
57 |
58 | var products = []Product{
59 | Product{Id: 1, Name: "Hover Shooters", Slug: "hover-shooters", Description: "Shoot your way to the top on 14 different hoverboards"},
60 | Product{Id: 2, Name: "Ocean Explorer", Slug: "ocean-explorer", Description: "Explore the depths of the sea in this one of a kind underwater experience"},
61 | Product{Id: 3, Name: "Dinosaur Park", Slug: "dinosaur-park", Description: "Go back 65 million years in the past and ride a T-Rex"},
62 | Product{Id: 4, Name: "Cars VR", Slug: "cars-vr", Description: "Get behind the wheel of the fastest cars in the world."},
63 | Product{Id: 5, Name: "Robin Hood", Slug: "robin-hood", Description: "Pick up the bow and arrow and master the art of archery"},
64 | Product{Id: 6, Name: "Real World VR", Slug: "real-world-vr", Description: "Explore the seven wonders of the world in VR"},
65 | }
66 |
67 | func getStatus(w http.ResponseWriter, r *http.Request) {
68 | w.Write([]byte("API is up and running"))
69 | }
70 |
71 | func getToken(w http.ResponseWriter, r *http.Request) {
72 | token := jwt.New(jwt.SigningMethodHS256)
73 | claims := token.Claims.(jwt.MapClaims)
74 | claims["admin"] = true
75 | claims["name"] = "Ado Kukic"
76 | claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
77 |
78 | tokenString, _ := token.SignedString(mySigningKey)
79 | w.Write([]byte(tokenString))
80 | }
81 |
82 | func getEmployees(w http.ResponseWriter, r *http.Request) {
83 | json.NewEncoder(w).Encode(employees)
84 | }
85 |
86 | func main() {
87 | muxRouter := mux.NewRouter().StrictSlash(true)
88 | muxRouter.HandleFunc("/status", getStatus).Methods("GET")
89 | muxRouter.HandleFunc("/get-token", getToken).Methods("GET")
90 | muxRouter.Handle("/employees", jwtMiddleware.Handler(http.HandlerFunc(getEmployees))).Methods("GET")
91 |
92 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, handlers.LoggingHandler(os.Stdout, router))
93 | if err != nil {
94 | log.Fatal("error starting http server : ", err)
95 | return
96 | }
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/chapter10/http-rest-api-secured.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "log"
6 | "net/http"
7 | "os"
8 | "time"
9 |
10 | jwtmiddleware "github.com/auth0/go-jwt-middleware"
11 | jwt "github.com/dgrijalva/jwt-go"
12 | "github.com/gorilla/handlers"
13 | "github.com/gorilla/mux"
14 | )
15 |
16 | const (
17 | CONN_HOST = "localhost"
18 | CONN_PORT = "8080"
19 | CLAIM_ISSUER = "Packt"
20 | CLAIM_EXPIRY_IN_HOURS = 24
21 | )
22 |
23 | type Employee struct {
24 | Id int `json:"id"`
25 | FirstName string `json:"firstName"`
26 | LastName string `json:"lastName"`
27 | }
28 |
29 | type Employees []Employee
30 |
31 | var employees []Employee
32 |
33 | func init() {
34 | employees = Employees{
35 | Employee{Id: 1, FirstName: "Foo", LastName: "Bar"},
36 | Employee{Id: 2, FirstName: "Baz", LastName: "Qux"},
37 | }
38 | }
39 |
40 | var signature = []byte("secret")
41 |
42 | var jwtMiddleware = jwtmiddleware.New(jwtmiddleware.Options{
43 | ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
44 | return signature, nil
45 | },
46 | SigningMethod: jwt.SigningMethodHS256,
47 | })
48 |
49 | func getToken(w http.ResponseWriter, r *http.Request) {
50 | claims := &jwt.StandardClaims{
51 | ExpiresAt: time.Now().Add(time.Hour * CLAIM_EXPIRY_IN_HOURS).Unix(),
52 | Issuer: CLAIM_ISSUER,
53 | }
54 | token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
55 | tokenString, _ := token.SignedString(signature)
56 | w.Write([]byte(tokenString))
57 | }
58 |
59 | func getStatus(w http.ResponseWriter, r *http.Request) {
60 | w.Write([]byte("API is up and running"))
61 | }
62 |
63 | func getEmployees(w http.ResponseWriter, r *http.Request) {
64 | json.NewEncoder(w).Encode(employees)
65 | }
66 |
67 | func main() {
68 | muxRouter := mux.NewRouter().StrictSlash(true)
69 | muxRouter.HandleFunc("/status", getStatus).Methods("GET")
70 | muxRouter.HandleFunc("/get-token", getToken).Methods("GET")
71 | muxRouter.Handle("/employees", jwtMiddleware.Handler(http.HandlerFunc(getEmployees))).Methods("GET")
72 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, handlers.LoggingHandler(os.Stdout, muxRouter))
73 | if err != nil {
74 | log.Fatal("error starting http server : ", err)
75 | return
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/chapter10/http-rest-api.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "log"
6 | "net/http"
7 | "os"
8 |
9 | "github.com/gorilla/handlers"
10 | "github.com/gorilla/mux"
11 | )
12 |
13 | const (
14 | CONN_HOST = "localhost"
15 | CONN_PORT = "8080"
16 | )
17 |
18 | type Employee struct {
19 | Id int `json:"id"`
20 | FirstName string `json:"firstName"`
21 | LastName string `json:"lastName"`
22 | }
23 |
24 | type Employees []Employee
25 |
26 | var employees []Employee
27 |
28 | func init() {
29 | employees = Employees{
30 | Employee{Id: 1, FirstName: "Foo", LastName: "Bar"},
31 | Employee{Id: 2, FirstName: "Baz", LastName: "Qux"},
32 | }
33 | }
34 |
35 | func getStatus(w http.ResponseWriter, r *http.Request) {
36 | w.Write([]byte("API is up and running"))
37 | }
38 |
39 | func getEmployees(w http.ResponseWriter, r *http.Request) {
40 | json.NewEncoder(w).Encode(employees)
41 | }
42 |
43 | func getToken(w http.ResponseWriter, r *http.Request) {
44 | w.Write([]byte("Not Implemented"))
45 | }
46 |
47 | func main() {
48 | router := mux.NewRouter().StrictSlash(true)
49 | router.HandleFunc("/status", getStatus).Methods("GET")
50 | router.HandleFunc("/get-token", getToken).Methods("GET")
51 | router.HandleFunc("/employees", getEmployees).Methods("GET")
52 | err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, handlers.LoggingHandler(os.Stdout, router))
53 | if err != nil {
54 | log.Fatal("error starting http server : ", err)
55 | return
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/chapter10/https-server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 | )
8 |
9 | const (
10 | CONN_HOST = "localhost"
11 | CONN_PORT = "8443"
12 | HTTPS_CERTIFICATE = "domain.crt"
13 | DOMAIN_PRIVATE_KEY = "domain.key"
14 | )
15 |
16 | func helloWorld(w http.ResponseWriter, r *http.Request) {
17 | fmt.Fprintf(w, "Hello World!")
18 | }
19 |
20 | func main() {
21 | http.HandleFunc("/", helloWorld)
22 | err := http.ListenAndServeTLS(CONN_HOST+":"+CONN_PORT, HTTPS_CERTIFICATE, DOMAIN_PRIVATE_KEY, nil)
23 | if err != nil {
24 | log.Fatal("error starting https server : ", err)
25 | return
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/chapter10/prevent-csrf.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "html/template"
6 | "log"
7 | "net/http"
8 |
9 | "github.com/gorilla/csrf"
10 | "github.com/gorilla/mux"
11 | )
12 |
13 | const (
14 | CONN_HOST = "localhost"
15 | CONN_PORT = "8443"
16 | HTTPS_CERTIFICATE = "domain.crt"
17 | DOMAIN_PRIVATE_KEY = "domain.key"
18 | )
19 |
20 | var AUTH_KEY = []byte("authentication-key")
21 |
22 | func signUp(w http.ResponseWriter, r *http.Request) {
23 | parsedTemplate, _ := template.ParseFiles("sign-up.html")
24 | err := parsedTemplate.Execute(w, map[string]interface{}{
25 | csrf.TemplateTag: csrf.TemplateField(r),
26 | })
27 | if err != nil {
28 | log.Printf("Error occurred while executing the template : ", err)
29 | return
30 | }
31 | }
32 |
33 | func post(w http.ResponseWriter, r *http.Request) {
34 | err := r.ParseForm()
35 | if err != nil {
36 | log.Print("error occurred while parsing form ", err)
37 | }
38 | name := r.FormValue("name")
39 | fmt.Fprintf(w, "Hi %s", name)
40 | }
41 |
42 | func main() {
43 | muxRouter := mux.NewRouter().StrictSlash(true)
44 | muxRouter.HandleFunc("/signup", signUp)
45 | muxRouter.HandleFunc("/post", post)
46 | http.ListenAndServeTLS(CONN_HOST+":"+CONN_PORT, HTTPS_CERTIFICATE, DOMAIN_PRIVATE_KEY, csrf.Protect(AUTH_KEY)(muxRouter))
47 | }
48 |
--------------------------------------------------------------------------------
/chapter10/sign-up.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Sign Up!
4 |
5 |
6 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/chapter11/.gitignore:
--------------------------------------------------------------------------------
1 | my-first-ec2-instance.pem
2 | copy-go-webapp-to-ec2/my-first-ec2-instance.pem
3 |
--------------------------------------------------------------------------------
/chapter11/copy-go-webapp-to-ec2/http-server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 | )
8 |
9 | const (
10 | CONN_PORT = "80"
11 | )
12 |
13 | func helloWorld(w http.ResponseWriter, r *http.Request) {
14 | fmt.Fprintf(w, "Hello World!")
15 | }
16 |
17 | func main() {
18 | http.HandleFunc("/", helloWorld)
19 | err := http.ListenAndServe(":"+CONN_PORT, nil)
20 | if err != nil {
21 | log.Fatal("error starting http server : ", err)
22 | return
23 | }
24 | }
25 |
--------------------------------------------------------------------------------