├── .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 |
8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /chapter02/templates/login-form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | First Form 4 | 5 | 6 |

Login

7 |
8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /chapter02/templates/upload-file.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | File Upload 5 | 6 | 7 |
8 | 9 | 10 | 11 |
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 |
8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /chapter03/templates/login-form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | First Form 4 | 5 | 6 |

Login

7 |
8 | 9 | 10 | 11 | 12 | 13 |
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 |
12 |
13 | Id :

14 | FirstName :

15 | LastName :

16 |

17 |
18 |

Output Message : {{message}}

19 |
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 | 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 |
41 | 42 | 43 |
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 | 16 | 17 | {employees} 18 | 19 |
FirstName
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 |
9 |

{{ message }}

10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
Add
27 |
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 | 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 | 8 | 9 | 10 | 11 | {{end}} 12 |
{{.Id}}{{.FirstName}}{{.LastName}}
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 |
7 | 8 | 9 | {{ .csrfField }} 10 | 11 |
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 | --------------------------------------------------------------------------------