Repository: shijuvar/go-recipes
Branch: master
Commit: 1ae756665620
Files: 103
Total size: 119.6 KB
Directory structure:
gitextract_fqtkzqqz/
├── .gitignore
├── LICENSE
├── README.md
├── binarypkg/
│ ├── src/
│ │ └── github.com/
│ │ └── shijuvar/
│ │ └── binarypkg/
│ │ └── utils.go
│ └── utils.go
├── binarypkgdemo/
│ └── main.go
├── ch01/
│ ├── declarations/
│ │ ├── enum.go
│ │ ├── main.go
│ │ └── main1.go
│ ├── favorites/
│ │ └── main.go
│ ├── hello/
│ │ └── main.go
│ ├── lib/
│ │ ├── favorites.go
│ │ └── utils.go
│ ├── loop/
│ │ └── main.go
│ ├── strutils/
│ │ └── utils.go
│ ├── strutilsdemo/
│ │ └── main.go
│ ├── typeconv/
│ │ └── main.go
│ └── vetting/
│ └── main.go
├── ch02/
│ ├── arrays/
│ │ └── main.go
│ ├── defer/
│ │ ├── deferfunc.go
│ │ └── panicrecover.go
│ ├── functions/
│ │ ├── calc.go
│ │ ├── closures.go
│ │ ├── swap.go
│ │ └── variadic.go
│ ├── maps/
│ │ ├── main.go
│ │ └── sort_map.go
│ └── slices/
│ ├── append.go
│ ├── append_nilslice.go
│ ├── copy.go
│ ├── iterate.go
│ ├── main.go
│ └── slicing.go
├── ch03/
│ ├── ecommerce/
│ │ ├── main.go
│ │ └── models.go
│ ├── employee/
│ │ └── employee.go
│ ├── person.go
│ └── pointer/
│ └── main.go
├── ch04/
│ ├── channels/
│ │ └── main.go
│ ├── deadlock/
│ │ ├── main.go
│ │ └── main_deadlock.go
│ ├── mathtable/
│ │ └── main.go
│ ├── pipeline/
│ │ ├── main.go
│ │ └── main1.go
│ ├── select/
│ │ ├── context.go
│ │ └── main.go
│ ├── unbuffercounter/
│ │ ├── main.go
│ │ └── main1.go
│ └── worker/
│ └── main.go
├── ch05/
│ ├── archivetar/
│ │ └── main.go
│ ├── archivezip/
│ │ └── main.go
│ ├── cmdflags/
│ │ └── main.go
│ ├── flag/
│ │ └── main.go
│ ├── json/
│ │ └── main.go
│ ├── jsontag/
│ │ └── main.go
│ ├── log/
│ │ ├── logger.go
│ │ └── main.go
│ └── simplelog/
│ └── main.go
├── ch06/
│ ├── influx/
│ │ └── main.go
│ ├── mongo/
│ │ ├── bookmark_store.go
│ │ └── main.go
│ ├── postgres/
│ │ └── main.go
│ └── rethink/
│ ├── bookmark_store.go
│ └── main.go
├── ch07/
│ ├── bookmarkapi/
│ │ ├── common/
│ │ │ ├── auth.go
│ │ │ ├── bootstrapper.go
│ │ │ ├── config.json
│ │ │ ├── logger.go
│ │ │ ├── mongo_utils.go
│ │ │ └── utils.go
│ │ ├── controllers/
│ │ │ ├── bookmark_controller.go
│ │ │ ├── resources.go
│ │ │ └── user_controller.go
│ │ ├── keys/
│ │ │ ├── app.rsa
│ │ │ └── app.rsa.pub
│ │ ├── main.go
│ │ ├── model/
│ │ │ └── models.go
│ │ ├── routers/
│ │ │ ├── bookmark.go
│ │ │ ├── routers.go
│ │ │ └── user.go
│ │ └── store/
│ │ ├── bookmark_store.go
│ │ └── user_store.go
│ ├── customhandler/
│ │ └── main.go
│ ├── defaultservemux/
│ │ └── main.go
│ ├── handlefunc/
│ │ └── main.go
│ ├── handlerfunc/
│ │ └── main.go
│ ├── httpserver/
│ │ └── main.go
│ ├── middleware/
│ │ └── main.go
│ └── server/
│ └── main.go
├── ch08/
│ ├── calc/
│ │ ├── calc.go
│ │ └── calc_test.go
│ ├── httpbdd/
│ │ ├── controllers/
│ │ │ ├── controllers_suite_test.go
│ │ │ ├── user_controller.go
│ │ │ └── user_controller_test.go
│ │ ├── main.go
│ │ ├── model/
│ │ │ └── user.go
│ │ └── store/
│ │ └── user_store.go
│ └── httptest/
│ ├── main.go
│ └── main_test.go
└── grpc/
├── client/
│ └── main.go
├── customer/
│ ├── customer.pb.go
│ └── customer.proto
└── server/
└── main.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
logs.txt
*.exe
*.test
*.prof
*.txt
debug
.vscode
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2016 Shiju Varghese
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# Go Recipes
Code examples for the book "Go Recipes" by Apress.
# gokit
Check out [github.com/shijuvar/gokit](https://github.com/shijuvar/gokit) for further examples on Go.
## Articles
* [Building High Performance APIs In Go Using gRPC And Protocol Buffers](https://medium.com/@shijuvar/building-high-performance-apis-in-go-using-grpc-and-protocol-buffers-2eda5b80771b)
* [Using Binary-Only Packages In Go](https://medium.com/@shijuvar/using-binary-only-packages-in-go-667bd7b123c8)
================================================
FILE: binarypkg/src/github.com/shijuvar/binarypkg/utils.go
================================================
//go:binary-only-package
package binarypkg
================================================
FILE: binarypkg/utils.go
================================================
package binarypkg
import "strings"
// ToUpperCase returns the string changed with upper case.
func ToUpperCase(s string) string {
return strings.ToUpper(s)
}
// ToLowerCase returns the string changed with lower case.
func ToLowerCase(s string) string {
return strings.ToLower(s)
}
================================================
FILE: binarypkgdemo/main.go
================================================
package main
import (
"fmt"
"github.com/shijuvar/go-recipes/binarypkg"
)
func main() {
str := "Golang"
// Convert to upper case
fmt.Println("To Upper Case:", binarypkg.ToUpperCase(str))
// Convert to lower case
fmt.Println("To Lower Case:", binarypkg.ToLowerCase(str))
}
================================================
FILE: ch01/declarations/enum.go
================================================
package main
import "fmt"
const (
// UNSPECIFIED logs nothing
UNSPECIFIED Level = iota // 0 :
// TRACE logs everything
TRACE // 1
// INFO logs Info, Warnings and Errors
INFO // 2
// WARNING logs Warning and Errors
WARNING // 3
// ERROR just logs Errors
ERROR // 4
)
// Level holds the log level.
type Level int
// levels provides the string name of Level
var levels = [...]string{
"UNSPECIFIED",
"TRACE",
"INFO",
"WARNING",
"ERROR",
}
// String returns the string value of level
func (l Level) String() string {
return levels[l]
}
func main() {
level := TRACE
if level == TRACE {
fmt.Println("TRACE")
}
level = INFO
fmt.Println(level.String())
}
================================================
FILE: ch01/declarations/main.go
================================================
package main
import "fmt"
// Declare constant
const Title = "Person Details"
// Declare package variable
var Country = "USA"
func main() {
fname, lname := "Shiju", "Varghese"
age := 35
// Print constant variable
fmt.Println(Title)
// Print local variables
fmt.Println("First Name:", fname)
fmt.Println("Last Name:", lname)
fmt.Println("Age:", age)
// Print package variable
fmt.Println("Country:", Country)
}
================================================
FILE: ch01/declarations/main1.go
================================================
package main
import "fmt"
// Declare constant
const Title string = "Person Details"
// Declare package variable
var Country string = "USA"
func main() {
var fname, lname string = "Shiju", "Varghese"
var age int = 35
// Print constant variable
fmt.Println(Title)
// Print local variables
fmt.Println("First Name:", fname)
fmt.Println("Last Name:", lname)
fmt.Println("Age:", age)
// Print package variable
fmt.Println("Country:", Country)
}
================================================
FILE: ch01/favorites/main.go
================================================
package main
import (
"fmt"
fav "github.com/shijuvar/go-recipes/ch01/lib"
)
func main() {
// Print default favorite packages
fmt.Println("****** Default favorite packages ******\n")
fav.PrintFavorites()
// Add couple of favorites
fav.Add("github.com/dgrijalva/jwt-go")
fav.Add("github.com/onsi/ginkgo")
fmt.Println("\n****** All favorite packages ******\n")
fav.PrintFavorites()
count := len(fav.GetAll())
fmt.Printf("Total packages in the favorite list:%d", count)
}
================================================
FILE: ch01/hello/main.go
================================================
package main
import "fmt"
func main() {
fmt.Println("Hello, World")
}
================================================
FILE: ch01/lib/favorites.go
================================================
package lib
// Stores favorites
var favorites []string
// Initialization logic for the package
func init() {
favorites = make([]string, 3)
favorites[0] = "github.com/gorilla/mux"
favorites[1] = "github.com/codegangsta/negroni"
favorites[2] = "gopkg.in/mgo.v2"
}
// Add a favorite into the in-memory collection
func Add(favorite string) {
favorites = append(favorites, favorite)
}
// Returns all favorite
func GetAll() []string {
return favorites
}
================================================
FILE: ch01/lib/utils.go
================================================
package lib
import (
"fmt"
)
// Print all favorites
func PrintFavorites() {
for _, v := range favorites {
fmt.Println(v)
}
}
================================================
FILE: ch01/loop/main.go
================================================
package main
import "fmt"
func main() {
sum()
sum1()
}
func sum() {
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
}
func sum1() {
sum := 1
for sum < 50 {
sum += sum
}
fmt.Println(sum)
}
================================================
FILE: ch01/strutils/utils.go
================================================
// Package strutils provides string utility functions
package strutils
import (
"strings"
"unicode"
)
// Returns the string changed with upper case.
func ToUpperCase(s string) string {
return strings.ToUpper(s)
}
// Returns the string changed with lower case.
func ToLowerCase(s string) string {
return strings.ToLower(s)
}
// Returns the string changed to upper case for its first letter.
func ToFirstUpper(s string) string {
if len(s) < 1 { // if the empty string
return s
}
// Trim the string
t := strings.Trim(s, " ")
// Convert all letters to lower case
t = strings.ToLower(t)
res := []rune(t)
// Convert first letter to upper case
res[0] = unicode.ToUpper(res[0])
return string(res)
}
================================================
FILE: ch01/strutilsdemo/main.go
================================================
package main
import (
"fmt"
"github.com/shijuvar/go-recipes/ch01/strutils"
)
func main() {
str1, str2 := "Golang", "gopher"
// Convert to upper case
fmt.Println("To Upper Case:", strutils.ToUpperCase(str1))
// Convert to lower case
fmt.Println("To Lower Case:", strutils.ToLowerCase(str1))
// Convert first letter to upper case
fmt.Println("To First Upper:", strutils.ToFirstUpper(str2))
}
================================================
FILE: ch01/typeconv/main.go
================================================
package main
import (
"fmt"
"reflect"
)
func main() {
// type conversion: dealing with a type
// The expression T(v) converts the value v to the type T
i := 100
f := float64(i)
fmt.Println(reflect.TypeOf(f))
// type assertion: dealing with an interface
// A type assertion provides access to an interface value's underlying concrete value
var x interface{} = 100 //float64(100)
y := x.(float64)
fmt.Println(reflect.TypeOf(y))
}
================================================
FILE: ch01/vetting/main.go
================================================
package main
import "fmt"
func main() {
floatValue:=4.99
fmt.Printf("The value is: %d",floatValue)
}
================================================
FILE: ch02/arrays/main.go
================================================
package main
import (
"fmt"
)
func main() {
// Declare arrays
var x [5]int
// Assign values at specific index
x[0] = 5
x[4] = 25
fmt.Println("Value of x:", x)
x[1] = 10
x[2] = 15
x[3] = 20
fmt.Println("Value of x:", x)
// Declare and initialize array with array literal
y := [5]int{10, 20, 30, 40, 50}
fmt.Println("Value of y:", y)
fmt.Println("Length of y:", len(y))
// Array literal with ...
z := [...]int{10, 20, 30, 40, 50}
fmt.Println("Value of z:", z)
fmt.Println("Length of z:", len(z))
// Initialize values at specific index with array literal
langs := [4]string{0: "Go", 3: "Julia"}
fmt.Println("Value of langs:", langs)
// Assign values to remain positions
langs[1] = "Rust"
langs[2] = "Scala"
// Iterate over the elements of array
fmt.Println("Value of langs:", langs)
fmt.Println("\nIterate over arrays\n")
for i := 0; i < len(langs); i++ {
fmt.Printf("langs[%d]:%s \n", i, langs[i])
}
fmt.Println("\n")
// Iterate over the elements of array using range
for k, v := range langs {
fmt.Printf("langs[%d]:%s \n", k, v)
}
for k := range langs {
fmt.Printf("Index:%d \n", k)
}
for _, v := range langs {
fmt.Printf("Value:%s \n", v)
}
}
================================================
FILE: ch02/defer/deferfunc.go
================================================
package main
import (
"fmt"
"io/ioutil"
"os"
)
func ReadFile(filename string) ([]byte, error) {
f, err := os.Open(filename)
if err != nil {
panic(err)
}
defer f.Close()
return ioutil.ReadAll(f)
}
func main() {
f, _ := ReadFile("test.txt")
fmt.Println("%s", f)
fmt.Println(string(f))
}
================================================
FILE: ch02/defer/panicrecover.go
================================================
package main
import (
"fmt"
)
func panicRecover() {
defer fmt.Println("Deferred call - 1")
defer func() {
fmt.Println("Deferred call - 2")
if e := recover(); e != nil {
// e is the value passed to panic()
fmt.Println("Recover with: ", e)
}
}()
panic("Just panicking for the sake of example")
fmt.Println("This will never be called")
}
func main() {
fmt.Println("Starting to panic")
panicRecover()
fmt.Println("Program regains control after the panic recovery")
}
================================================
FILE: ch02/functions/calc.go
================================================
package main
import (
"fmt"
)
func Add(x, y int) int {
return x + y
}
func Subtract(x, y int) int {
return x - y
}
func main() {
x, y := 20, 10
result := Add(x, y)
fmt.Println("[Add]:", result)
result = Subtract(x, y)
fmt.Println("[Subtract]:", result)
}
================================================
FILE: ch02/functions/closures.go
================================================
package main
import (
"fmt"
)
func SplitValues(f func(sum int) (int, int)) {
x, y := f(35)
fmt.Println(x, y)
x, y = f(50)
fmt.Println(x, y)
}
func main() {
a, b := 5, 8
fn := func(sum int) (int, int) {
x := sum * a / b
y := sum - x
return x, y
}
// Passing function value as an argument to another function
SplitValues(fn)
// Calling the function value by providing argument
x, y := fn(20)
fmt.Println(x, y)
}
================================================
FILE: ch02/functions/swap.go
================================================
package main
import (
"fmt"
)
func Swap(x, y string) (string, string) {
return y, x
}
func main() {
x, y := "Shiju", "Varghese"
fmt.Println("Before Swap:", x, y)
x, y = Swap(x, y)
fmt.Println("After Swap:", x, y)
}
================================================
FILE: ch02/functions/variadic.go
================================================
package main
import (
"fmt"
)
func Sum(nums ...int) int {
total := 0
for _, num := range nums {
total += num
}
return total
}
func main() {
// Providing four arguments
total := Sum(1, 2, 3, 4)
fmt.Println("The Sum is:", total)
// Providing three arguments
total = Sum(5, 7, 8)
fmt.Println("The Sum is:", total)
// Providing a Slice as an argument
nums := []int{1, 2, 3, 4, 5}
total = Sum(nums...)
fmt.Println("The Sum is:", total)
}
================================================
FILE: ch02/maps/main.go
================================================
package main
import (
"fmt"
)
func main() {
// Declares a nil map
var chapts map[int]string
// Initialize map with make function
chapts = make(map[int]string)
// Add data as key/value pairs
chapts[1] = "Beginning Go"
chapts[2] = "Go Fundamentals"
chapts[3] = "Structs and Interfaces"
// Iterate over the elements of map using range
for k, v := range chapts {
fmt.Printf("Key: %d Value: %s\n", k, v)
}
// Declare and initialize map using map literal
langs := map[string]string{
"EL": "Greek",
"EN": "English",
"ES": "Spanish",
"FR": "French",
"HI": "Hindi",
}
// Delete an element
delete(langs, "EL")
// Lookout an element with key
if lan, ok := langs["EL"]; ok {
fmt.Println(lan)
} else {
fmt.Println("\nKey doesn't exists")
}
// Passing a map to function doesn't make a copy
removeLan(langs, "HI")
for k, v := range langs {
fmt.Printf("Key: %s Value: %s\n", k, v)
}
}
func removeLan(langs map[string]string, key string) {
delete(langs, key)
}
================================================
FILE: ch02/maps/sort_map.go
================================================
package main
import (
"fmt"
"sort"
)
func main() {
// Initialize map with make function
chapts := make(map[int]string)
// Add data as key/value pairs
chapts[1] = "Beginning Go"
chapts[2] = "Go Fundamentals"
chapts[3] = "Structs and Interfaces"
for k, v := range chapts {
fmt.Println(k, v)
}
// Slice for specifying the order of the map
var keys []int
// Appending keys of the map
for k := range chapts {
keys = append(keys, k)
}
// Ints sorts a slice of ints in increasing order.
sort.Ints(keys)
// Iterate over the map with an order
for _, k := range keys {
fmt.Println("Key:", k, "Value:", chapts[k])
}
}
================================================
FILE: ch02/slices/append.go
================================================
package main
import (
"fmt"
)
func main() {
x := make([]int, 2, 5)
x[0] = 10
x[1] = 20
fmt.Println("Slice x:", x)
fmt.Printf("Length is %d Capacity is %d\n", len(x), cap(x))
// Create a bigger slice
x = append(x, 30, 40, 50)
fmt.Println("Slice x after appending data:", x)
fmt.Printf("Length is %d Capacity is %d\n", len(x), cap(x))
x = append(x, 60, 70, 80)
fmt.Println("Slice x after appending data for the second time:", x)
fmt.Printf("Length is %d Capacity is %d\n", len(x), cap(x))
}
================================================
FILE: ch02/slices/append_nilslice.go
================================================
package main
import "fmt"
func main() {
// Declare a nil slice
var x []int
fmt.Println(x, len(x), cap(x))
x = append(x, 10, 20, 30)
fmt.Println("Slice x after appending data:", x)
}
================================================
FILE: ch02/slices/copy.go
================================================
package main
import (
"fmt"
)
func main() {
x := []int{10, 20, 30}
fmt.Printf("[Slice:x] Length is %d Capacity is %d\n", len(x), cap(x))
// Create a bigger slice
y := make([]int, 5, 10)
copy(y, x)
fmt.Printf("[Slice:y] Length is %d Capacity is %d\n", len(y), cap(y))
fmt.Println("Slice y after copying:", y)
y[3] = 40
y[4] = 50
fmt.Println("Slice y after adding elements:", y)
}
================================================
FILE: ch02/slices/iterate.go
================================================
package main
import (
"fmt"
)
func main() {
x := []int{10, 20, 30, 40, 50}
for k, v := range x {
fmt.Printf("x[%d]: %d\n", k, v)
}
}
================================================
FILE: ch02/slices/main.go
================================================
package main
import (
"fmt"
)
func main() {
x := make([]int, 3, 5)
x[0] = 10
x[1] = 20
x[2] = 30
fmt.Println(x)
fmt.Println(len(x))
fmt.Println(cap(x))
y := make([]int, 3)
y[0] = 10
y[1] = 20
y[2] = 30
fmt.Println(y)
fmt.Println(len(y))
fmt.Println(cap(y))
z := []int{10, 20, 30}
fmt.Println(len(z))
fmt.Println(cap(z))
z1 := []int{0: 10, 2: 30}
fmt.Println(len(z1))
fmt.Println(cap(z1))
x1 := []int{10, 20, 30}
y1 := append(x1, 40, 50)
fmt.Println(x1, y1)
}
================================================
FILE: ch02/slices/slicing.go
================================================
package main
import (
"fmt"
)
func main() {
x := []int{10, 20, 30, 40, 50}
y := x[1:3]
fmt.Println("y:", y)
fmt.Println(len(y))
fmt.Println(cap(y))
z := x[:3]
fmt.Println("z:", z)
fmt.Println(len(z))
fmt.Println(cap(z))
x1 := x[:]
fmt.Println("x1:", x1)
fmt.Println(len(x1))
fmt.Println(cap(x1))
x1[4] = 75
fmt.Println("x:", x)
fmt.Println("x1:", x1)
}
================================================
FILE: ch03/ecommerce/main.go
================================================
package main
import (
"fmt"
"time"
)
func main() {
order := &Order{
Id: 1001,
Customer: Customer{
FirstName: "Alex",
LastName: "John",
Email: "alex@email.com",
Phone: "732-757-2923",
Addresses: []Address{
Address{
Street: "1 Mission Street",
City: "San Francisco",
State: "CA",
Zip: "94105",
IsShippingAddress: true,
},
Address{
Street: "49 Stevenson Street",
City: "San Francisco",
State: "CA",
Zip: "94105",
},
},
},
Status: "Placed",
PlacedOn: time.Date(2016, time.April, 10, 0, 0, 0, 0, time.UTC),
OrderItems: []OrderItem{
OrderItem{
Product: Product{
Code: "knd100",
Name: "Kindle Voyage",
Description: "Kindle Voyage Wifi, 6 High-Resolution Display",
UnitPrice: 220,
},
Quantity: 1,
},
OrderItem{
Product: Product{
Code: "fint101",
Name: "Kindle Case",
Description: "Fintie Kindle Voyage SmartShell Case",
UnitPrice: 10,
},
Quantity: 2,
},
},
}
fmt.Println(order.ToString())
// Change Order status
order.ChangeStatus("Processing")
fmt.Println("\n")
fmt.Println(order.ToString())
}
================================================
FILE: ch03/ecommerce/models.go
================================================
package main
import (
"fmt"
"time"
)
type Address struct {
Street, City, State, Zip string
IsShippingAddress bool
}
type Customer struct {
FirstName, LastName, Email, Phone string
Addresses []Address
}
func (c Customer) ToString() string {
return fmt.Sprintf("Customer: %s %s, Email:%s", c.FirstName, c.LastName, c.Email)
}
func (c Customer) ShippingAddress() string {
for _, v := range c.Addresses {
if v.IsShippingAddress == true {
return fmt.Sprintf("%s, %s, %s, Zip - %s", v.Street, v.City, v.State, v.Zip)
}
}
return ""
}
type Order struct {
Id int
Customer
PlacedOn time.Time
Status string
OrderItems []OrderItem
}
func (o *Order) GrandTotal() float64 {
var total float64
for _, v := range o.OrderItems {
total += v.Total()
}
return total
}
func (o *Order) ToString() string {
var orderStr string
orderStr = fmt.Sprintf("Order#:%d, OrderDate:%s, Status:%s, Grand Total:%f\n", o.Id, o.PlacedOn, o.Status, o.GrandTotal())
orderStr += o.Customer.ToString()
orderStr += fmt.Sprintf("\nOrder Items:")
for _, v := range o.OrderItems {
orderStr += fmt.Sprintf("\n")
orderStr += v.ToString()
}
orderStr += fmt.Sprintf("\nShipping Address:")
orderStr += o.Customer.ShippingAddress()
return orderStr
}
func (o *Order) ChangeStatus(newStatus string) {
o.Status = newStatus
}
type OrderItem struct {
Product
Quantity int
}
func (item OrderItem) Total() float64 {
return float64(item.Quantity) * item.Product.UnitPrice
}
func (item OrderItem) ToString() string {
itemStr := fmt.Sprintf("Code:%s, Product:%s -- %s, UnitPrice:%f, Quantity:%d, Total:%f",
item.Product.Code, item.Product.Name, item.Product.Description, item.Product.UnitPrice, item.Quantity, item.Total())
return itemStr
}
type Product struct {
Code, Name, Description string
UnitPrice float64
}
================================================
FILE: ch03/employee/employee.go
================================================
// Example program with Interface, Composition and Method Overriding
package main
import (
"fmt"
"time"
)
type TeamMember interface {
PrintName()
PrintDetails()
}
type Employee struct {
FirstName, LastName string
Dob time.Time
JobTitle, Location string
}
func (e Employee) PrintName() {
fmt.Printf("\n%s %s\n", e.FirstName, e.LastName)
}
func (e Employee) PrintDetails() {
fmt.Printf("Date of Birth: %s, Job: %s, Location: %s\n", e.Dob.String(), e.JobTitle, e.Location)
}
type Developer struct {
Employee //type embedding for composition
Skills []string
}
// Overrides the PrintDetails
func (d Developer) PrintDetails() {
// Call Employee PrintDetails
d.Employee.PrintDetails()
fmt.Println("Technical Skills:")
for _, v := range d.Skills {
fmt.Println(v)
}
}
type Manager struct {
Employee //type embedding for composition
Projects []string
Locations []string
}
// Overrides the PrintDetails
func (m Manager) PrintDetails() {
// Call Employee PrintDetails
m.Employee.PrintDetails()
fmt.Println("Projects:")
for _, v := range m.Projects {
fmt.Println(v)
}
fmt.Println("Managing teams for the locations:")
for _, v := range m.Locations {
fmt.Println(v)
}
}
type Team struct {
Name, Description string
TeamMembers []TeamMember
}
func (t Team) PrintTeamDetails() {
fmt.Printf("Team: %s - %s\n", t.Name, t.Description)
fmt.Println("Details of the team members:")
for _, v := range t.TeamMembers {
v.PrintName()
v.PrintDetails()
}
}
func main() {
steve := Developer{
Employee: Employee{
FirstName: "Steve",
LastName: "John",
Dob: time.Date(1990, time.February, 17, 0, 0, 0, 0, time.UTC),
JobTitle: "Software Engineer",
Location: "San Fancisco",
},
Skills: []string{"Go", "Docker", "Kubernetes"},
}
irene := Developer{
Employee: Employee{
FirstName: "Irene",
LastName: "Rose",
Dob: time.Date(1991, time.January, 13, 0, 0, 0, 0, time.UTC),
JobTitle: "Software Engineer",
Location: "Santa Clara",
},
Skills: []string{"Go", "MongoDB"},
}
alex := Manager{
Employee: Employee{
FirstName: "Alex",
LastName: "Williams",
Dob: time.Date(1979, time.February, 17, 0, 0, 0, 0, time.UTC),
JobTitle: "Program Manger",
Location: "Santa Clara",
},
Projects: []string{"CRM", "e-Commerce"},
Locations: []string{"San Fancisco", "Santa Clara"},
}
// Create team
team := Team{
"Go",
"Golang Engineering Team",
[]TeamMember{steve, irene, alex},
}
// Get details of Team
team.PrintTeamDetails()
}
================================================
FILE: ch03/person.go
================================================
// Person struct with methods of pointer receiver
package main
import (
"fmt"
"time"
)
// Person struct
type Person struct {
FirstName, LastName string
Dob time.Time
Email, Location string
}
// PrintName prints the name of the Person
func (p Person) PrintName() {
fmt.Printf("\n%s %s\n", p.FirstName, p.LastName)
}
// PrintDetails prints the details of Person
func (p Person) PrintDetails() {
fmt.Printf("[Date of Birth: %s, Email: %s, Location: %s ]\n", p.Dob.String(), p.Email, p.Location)
}
func main() {
/*
// Declare a Person variable using var
var p Person
// Assign values to fields
p.FirstName="Shiju"
p.LastName="Varghese"
p.Dob= time.Date(1979, time.February, 17, 0, 0, 0, 0, time.UTC)
p.Email="shiju@email.com"
p.Location= "Kochi"
// Declare a Person variable and initialize values using Struct literal
p := Person{
"Shiju",
"Varghese",
time.Date(1979, time.February, 17, 0, 0, 0, 0, time.UTC),
"shiju@email.com",
"Kochi",
}
*/
p := Person{
FirstName: "Shiju",
LastName: "Varghese",
Dob: time.Date(1979, time.February, 17, 0, 0, 0, 0, time.UTC),
Email: "shiju@email.com",
Location: "Kochi",
}
p.PrintName()
p.PrintDetails()
}
================================================
FILE: ch03/pointer/main.go
================================================
// Person struct with methods of pointer receiver
package main
import (
"fmt"
"time"
)
type Person struct {
FirstName, LastName string
Dob time.Time
Email, Location string
}
//A person method with pointer receiver
func (p *Person) PrintName() {
fmt.Printf("\n%s %s\n", p.FirstName, p.LastName)
}
//A person method with pointer receiver
func (p *Person) PrintDetails() {
fmt.Printf("[Date of Birth: %s, Email: %s, Location: %s ]\n", p.Dob.String(), p.Email, p.Location)
}
//A person method with pointer receiver
func (p *Person) ChangeLocation(newLocation string) {
p.Location = newLocation
}
func main() {
p := &Person{
"Shiju",
"Varghese",
time.Date(1979, time.February, 17, 0, 0, 0, 0, time.UTC),
"shiju@email.com",
"Kochi",
}
p.ChangeLocation("Santa Clara")
p.PrintName()
p.PrintDetails()
}
================================================
FILE: ch04/channels/main.go
================================================
package main
import (
"fmt"
)
func main() {
// Declare a unbuffered channel
counter := make(chan int)
// Creates a buffered channel with capacity of 3
nums := make(chan int, 3)
go func() {
// Send value to the unbuffered channel
counter <- 1
close(counter) // Closes the channel
}()
go func() {
// Send values to the buffered channel
nums <- 10
nums <- 30
nums <- 50
}()
// Read the value from unbuffered channel
fmt.Println(<-counter)
val, ok := <-counter // Trying to read from closed channel
if ok {
fmt.Println(val) // This won't execute
}
// Read the 3 buffered values from the buffered channel
fmt.Println(<-nums)
fmt.Println(<-nums)
fmt.Println(<-nums)
close(nums) // Closes the channel
}
================================================
FILE: ch04/deadlock/main.go
================================================
package main
import (
"fmt"
)
func main() {
// Declare a unbuffered channel
counter := make(chan int)
// Perform send operation by launching new goroutine
go func() {
counter <- 10
}()
fmt.Println(<-counter) // Receive operation from the channel
}
================================================
FILE: ch04/deadlock/main_deadlock.go
================================================
package main
import (
"fmt"
)
func main() {
// Declare a unbuffered channel
counter := make(chan int)
// This will create a deadlock
counter <- 10 // Send operation to a channel from main goroutine
fmt.Println(<-counter) // Receive operation from the channel
}
================================================
FILE: ch04/mathtable/main.go
================================================
// This sample program demonstrates how to create goroutines
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
// WaitGroup is used to wait for the program to finish goroutines.
var wg sync.WaitGroup
func main() {
// Add a count of two, one for each goroutine.
wg.Add(2)
fmt.Println("Start Goroutines")
// Launch functions as goroutines
go addTable()
go multiTable()
// Wait for the goroutines to finish.
fmt.Println("Waiting To Finish")
wg.Wait()
fmt.Println("\nTerminating Program")
}
func addTable() {
// Schedule the call to WaitGroup's Done to tell goroutine is completed.
defer wg.Done()
for i := 1; i <= 10; i++ {
sleep := rand.Int63n(1000)
time.Sleep(time.Duration(sleep) * time.Millisecond)
fmt.Println("Addition Table for:", i)
for j := 1; j <= 10; j++ {
//res = i + j
fmt.Printf("%d+%d=%d\t", i, j, i+j)
}
fmt.Println("\n")
}
}
func multiTable() {
// Schedule the call to WaitGroup's Done to tell goroutine is completed.
defer wg.Done()
for i := 1; i <= 10; i++ {
sleep := rand.Int63n(1000)
time.Sleep(time.Duration(sleep) * time.Millisecond)
fmt.Println("Multiplication Table for:", i)
for j := 1; j <= 10; j++ {
//res = i + j
fmt.Printf("%d*%d=%d\t", i, j, i*j)
}
fmt.Println("\n")
}
}
================================================
FILE: ch04/pipeline/main.go
================================================
package main
import (
"fmt"
"math"
"math/rand"
"sync"
)
type fibvalue struct {
input, value int
}
var wg sync.WaitGroup
func randomCounter(out chan<- int) {
defer wg.Done()
var random int
for x := 0; x < 10; x++ {
random = rand.Intn(50)
out <- random
}
close(out)
}
func generateFibonacci(out chan<- fibvalue, in <-chan int) {
defer wg.Done()
var input float64
for v := range in {
input = float64(v)
// Fibonacci using Binet's formula
Phi := (1 + math.Sqrt(5)) / 2
phi := (1 - math.Sqrt(5)) / 2
result := (math.Pow(Phi, input) - math.Pow(phi, input)) / math.Sqrt(5)
out <- fibvalue{
input: v,
value: int(result),
}
}
close(out)
}
func printFibonacci(in <-chan fibvalue) {
defer wg.Done()
for v := range in {
fmt.Printf("Fibonacci value of %d is %d\n", v.input, v.value)
}
}
func main() {
// Add 3 into WaitGroup Counter
wg.Add(3)
// Declare Channels
randoms := make(chan int)
fibs := make(chan fibvalue)
// Launching 3 goroutines
go randomCounter(randoms)
go generateFibonacci(fibs, randoms)
go printFibonacci(fibs)
// Wait for completing all goroutines
wg.Wait()
}
================================================
FILE: ch04/pipeline/main1.go
================================================
package main
import (
"fmt"
"math"
"math/rand"
"sync"
)
type fibvalue struct {
input, value int
}
var wg sync.WaitGroup
// Generates random values
func randomCounter(out chan int) {
defer wg.Done()
var random int
for x := 0; x < 10; x++ {
random = rand.Intn(50)
out <- random
}
close(out)
}
// Produces fibonacci values of inputs provided by randomCounter
func generateFibonacci(out chan fibvalue, in chan int) {
defer wg.Done()
var input float64
for v := range in {
input = float64(v)
// Fibonacci using Binet's formula
Phi := (1 + math.Sqrt(5)) / 2
phi := (1 - math.Sqrt(5)) / 2
result := (math.Pow(Phi, input) - math.Pow(phi, input)) / math.Sqrt(5)
out <- fibvalue{
input: v,
value: int(result),
}
}
close(out)
}
// Print fibonacci values generated by generateFibonacci
func printFibonacci(in chan fibvalue) {
defer wg.Done()
for v := range in {
fmt.Printf("Fibonacci value of %d is %d\n", v.input, v.value)
}
}
func main() {
// Add 3 into WaitGroup Counter
wg.Add(3)
// Declare Channels
randoms := make(chan int)
fibs := make(chan fibvalue)
// Launching 3 goroutines
go randomCounter(randoms) // First stage of pipeline
go generateFibonacci(fibs, randoms) // Second stage of pipeline
go printFibonacci(fibs) // Third stage of pipeline
// Wait for completing all goroutines
wg.Wait()
}
================================================
FILE: ch04/select/context.go
================================================
package main
import (
"context"
"fmt"
)
func generateValues(ctx context.Context, counter chan int) {
n := 1
for {
select {
case <-ctx.Done():
return
case counter <- n:
n++
}
}
}
func main() {
// WithCancel returns a copy of parent with a new Done channel. The returned
// context's Done channel is closed when the returned cancel function is called
// or when the parent context's Done channel is closed, whichever happens first.
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this Context complete.
ctx, cancel := context.WithCancel(context.Background())
// ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
counter := make(chan int)
defer cancel()
go generateValues(ctx, counter)
for n := range counter {
fmt.Println(n)
if n == 10 {
cancel()
break
}
}
}
================================================
FILE: ch04/select/main.go
================================================
package main
import (
"fmt"
"math"
"math/rand"
"sync"
)
type (
fibvalue struct {
input, value int
}
squarevalue struct {
input, value int
}
)
func generateSquare(sqrs chan<- squarevalue) {
defer wg.Done()
for i := 1; i <= 10; i++ {
num := rand.Intn(50)
sqrs <- squarevalue{
input: num,
value: num * num,
}
}
}
func generateFibonacci(fibs chan<- fibvalue) {
defer wg.Done()
for i := 1; i <= 10; i++ {
num := float64(rand.Intn(50))
// Fibonacci using Binet's formula
Phi := (1 + math.Sqrt(5)) / 2
phi := (1 - math.Sqrt(5)) / 2
result := (math.Pow(Phi, num) - math.Pow(phi, num)) / math.Sqrt(5)
fibs <- fibvalue{
input: int(num),
value: int(result),
}
}
}
func printValues(fibs <-chan fibvalue, sqrs <-chan squarevalue) {
defer wg.Done()
for i := 1; i <= 20; i++ {
select {
case fib := <-fibs:
fmt.Printf("Fibonacci value of %d is %d\n", fib.input, fib.value)
case sqr := <-sqrs:
fmt.Printf("Square value of %d is %d\n", sqr.input, sqr.value)
}
}
}
// wg is used to wait for the program to finish.
var wg sync.WaitGroup
func main() {
wg.Add(3)
// Create Channels
fibs := make(chan fibvalue)
sqrs := make(chan squarevalue)
// Launching 3 goroutines
go generateFibonacci(fibs)
go generateSquare(sqrs)
go printValues(fibs, sqrs)
// Wait for completing all goroutines
wg.Wait()
}
================================================
FILE: ch04/unbuffercounter/main.go
================================================
// Example program with unbuffered channel
package main
import (
"fmt"
"sync"
)
// wg is used to wait for the program to finish.
var wg sync.WaitGroup
func main() {
count := make(chan int)
// Add a count of two, one for each goroutine.
wg.Add(2)
fmt.Println("Start Goroutines")
// Launch a goroutine with label "Goroutine-1"
go printCounts("Goroutine-1", count)
// Launch a goroutine with label "Goroutine-2"
go printCounts("Goroutine-2", count)
fmt.Println("Communication of channel begins")
count <- 1
// Wait for the goroutines to finish.
fmt.Println("Waiting To Finish")
wg.Wait()
fmt.Println("\nTerminating the Program")
}
func printCounts(label string, count chan int) {
// Schedule the call to WaitGroup's Done to tell goroutine is completed.
defer wg.Done()
for val := range count {
fmt.Printf("Count: %d received from %s \n", val, label)
if val == 10 {
fmt.Printf("Channel Closed from %s \n", label)
// Close the channel
close(count)
return
}
val++
// Send count back to the other goroutine.
count <- val
}
}
================================================
FILE: ch04/unbuffercounter/main1.go
================================================
// Example program with unbuffered channel
package main
import (
"fmt"
"sync"
)
// wg is used to wait for the program to finish.
var wg sync.WaitGroup
func main() {
count := make(chan int)
// Add a count of two, one for each goroutine.
wg.Add(2)
fmt.Println("Start Goroutines")
// Launch a goroutine with label "Goroutine-1"
go printCounts("Goroutine-1", count)
// Launch a goroutine with label "Goroutine-2"
go printCounts("Goroutine-2", count)
fmt.Println("Communication of channel begins")
count <- 1
// Wait for the goroutines to finish.
fmt.Println("Waiting To Finish")
wg.Wait()
fmt.Println("\nTerminating the Program")
}
func printCounts(label string, count chan int) {
// Schedule the call to WaitGroup's Done to tell goroutine is completed.
defer wg.Done()
for {
// Receives message from Channel
val, ok := <-count
if !ok {
fmt.Println("Channel was closed")
return
}
fmt.Printf("Count: %d received from %s \n", val, label)
if val == 10 {
fmt.Printf("Channel Closed from %s \n", label)
// Close the channel
close(count)
return
}
val++
// Send count back to the other goroutine.
count <- val
}
}
================================================
FILE: ch04/worker/main.go
================================================
// This sample program demonstrates how to use a buffered
// channel to work on multiple tasks with a predefined number
// of goroutines.
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
type Task struct {
Id int
JobId int
Status string
CreatedOn time.Time
}
func (t *Task) Run() {
sleep := rand.Int63n(1000)
// Delaying the execution for the sake of example
time.Sleep(time.Duration(sleep) * time.Millisecond)
t.Status = "Completed"
}
// wg is used to wait for the program to finish.
var wg sync.WaitGroup
const noOfWorkers = 3
// main is the entry point for all Go programs.
func main() {
// Create a buffered channel to manage the task queue.
taskQueue := make(chan *Task, 10)
// Launch goroutines to handle the work.
// The worker process is distributing with the value of noOfWorkers.
wg.Add(noOfWorkers)
for gr := 1; gr <= noOfWorkers; gr++ {
go worker(taskQueue, gr)
}
// Add Tasks into Buffered channel.
for i := 1; i <= 10; i++ {
taskQueue <- &Task{
Id: i,
JobId: 100 + i,
CreatedOn: time.Now(),
}
}
// Close the channel
close(taskQueue)
// Wait for all the work to get done.
wg.Wait()
}
// worker is launched as a goroutine to process Tasks from
// the buffered channel.
func worker(taskQueue <-chan *Task, workerId int) {
// Schedule the call to Done method of WaitGroup.
defer wg.Done()
for v := range taskQueue {
fmt.Printf("Worker%d: received request for Task:%d - Job:%d\n", workerId, v.Id, v.JobId)
v.Run()
// Display we finished the work.
fmt.Printf("Worker%d: Status:%s for Task:%d - Job:%d\n", workerId, v.Status, v.Id, v.JobId)
}
}
================================================
FILE: ch05/archivetar/main.go
================================================
package main
import (
"archive/tar"
"fmt"
"io"
"log"
"os"
)
// addToArchive writes a given file into a .tar file
// Returns nill if the operation is succeeded
func addToArchive(filename string, tw *tar.Writer) error {
// Open the file to archive into tar file.
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
// Get the FileInfo struct that describe the file.
fileinfo, err := file.Stat()
// Create a pointer to tar.Header struct
hdr := &tar.Header{
ModTime: fileinfo.ModTime(), // modified time
Name: filename, // name of header
Size: fileinfo.Size(), // length in bytes
Mode: int64(fileinfo.Mode().Perm()), // permission and mode bits
}
// WriteHeader writes tar.Header and prepares to accept the file's contents.
if err := tw.WriteHeader(hdr); err != nil {
return err
}
// Write the file contents to the tar file.
copied, err := io.Copy(tw, file)
if err != nil {
return err
}
// Check the size of copied file with the source file.
if copied < fileinfo.Size() {
return fmt.Errorf("Size of the copied file doesn't match with source file %s: %s", filename, err)
}
return nil
}
// archiveFiles archives a group of given files into a tar file.
func archiveFiles(files []string, archive string) error {
// Flags for open the tar file.
flags := os.O_WRONLY | os.O_CREATE | os.O_TRUNC
// Open the tar file
file, err := os.OpenFile(archive, flags, 0644)
if err != nil {
return err
}
defer file.Close()
// Create a new Writer writing to given file object.
// Writer provides sequential writing of a tar archive in POSIX.1 format.
tw := tar.NewWriter(file)
defer tw.Close()
// Iterate through the files to write each file into the tar file.
for _, filename := range files {
// Write the file into tar file.
if err := addToArchive(filename, tw); err != nil {
return err
}
}
return nil
}
// readArchive reads the file contents from tar file.
func readArchive(archive string) error {
// Open the tar archive file.
file, err := os.Open(archive)
if err != nil {
return err
}
defer file.Close()
// Create the tar.Reader to read the tar archive.
// A Reader provides sequential access to the contents of a tar archive.
tr := tar.NewReader(file)
// Iterate through the files in the tar archive.
for {
hdr, err := tr.Next()
if err == io.EOF {
// End of tar archive
fmt.Println("end")
break
}
if err != nil {
return err
}
size := hdr.Size
contents := make([]byte, size)
read, err := io.ReadFull(tr, contents)
// Check the size of file contents
if int64(read) != size {
return fmt.Errorf("Size of the opened file doesn't match with the file %s", hdr.Name)
}
// hdr.Name returns the file name.
fmt.Printf("Contents of the file %s:\n", hdr.Name)
// Writing the file contents into Stdout.
fmt.Fprintf(os.Stdout, "\n%s", contents)
}
return nil
}
func main() {
// Name of the tar file
archive := "source.tar"
// Files to be archived in tar format
files := []string{"main.go", "readme.txt"}
// Archive files into tar format
err := archiveFiles(files, archive)
if err != nil {
log.Fatalf("Error while writing to tar file:%s", err)
}
// Archiving is sucsess.
fmt.Println("The tar file source.tar has been created")
// Read the file contents of tar file
err = readArchive(archive)
if err != nil {
log.Fatalf("Error while reading the tar file:%s", err)
}
}
================================================
FILE: ch05/archivezip/main.go
================================================
package main
import (
"archive/zip"
"fmt"
"io"
"log"
"os"
)
// addToArchive writes a given file into a zip file.
func addToArchive(filename string, zw *zip.Writer) error {
// Open the given file to archive into a zip file.
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
// Create adds a file to the zip file using the given name/
// Create returns a io.Writer to which the file contents should be written.
wr, err := zw.Create(filename)
if err != nil {
return err
}
// Write the file contents to the zip file.
if _, err := io.Copy(wr, file); err != nil {
return err
}
return nil
}
// archiveFiles archives a group of given files into a zip file.
func archiveFiles(files []string, archive string) error {
flags := os.O_WRONLY | os.O_CREATE | os.O_TRUNC
// Open the tar file
file, err := os.OpenFile(archive, flags, 0644)
if err != nil {
return err
}
defer file.Close()
// Create zip.Writer that implements a zip file writer.
zw := zip.NewWriter(file)
defer zw.Close()
// Iterate through the files to write each file into the zip file.
for _, filename := range files {
// Write the file into tar file.
if err := addToArchive(filename, zw); err != nil {
return err
}
}
return nil
}
// readArchive reads the file contents from tar file.
func readArchive(archive string) error {
// Open the zip file specified by name and return a ReadCloser.
rc, err := zip.OpenReader(archive)
if err != nil {
return err
}
defer rc.Close()
// Iterate through the files in the zip file to read the file contents.
for _, file := range rc.File {
frc, err := file.Open()
if err != nil {
return err
}
defer frc.Close()
fmt.Fprintf(os.Stdout, "Contents of the file %s:\n", file.Name)
// Write the contents into Stdout
copied, err := io.Copy(os.Stdout, frc)
if err != nil {
return err
}
// Check the size of the file.
if uint64(copied) != file.UncompressedSize64 {
return fmt.Errorf("Length of the file contents doesn't match with the file %s", file.Name)
}
fmt.Println()
}
return nil
}
func main() {
// Name of the zip file
archive := "source.zip"
// Files to be archived in zip format.
files := []string{"main.go", "readme.txt"}
// Archive files into zip format.
err := archiveFiles(files, archive)
if err != nil {
log.Fatalf("Error while writing to zip file:%s\n", err)
}
// Read the file contents of tar file.
err = readArchive(archive)
if err != nil {
log.Fatalf("Error while reading the zip file:%s\n", err)
}
}
================================================
FILE: ch05/cmdflags/main.go
================================================
package main
import (
"flag"
"fmt"
)
func main() {
fileName := flag.String("filename", "logfile", "File name for the log file")
logLevel := flag.Int("loglevel", 0, "An integer value for Level (0-4)")
isEnable := flag.Bool("enable", false, "A boolean value for enabling log options")
var num int
// Bind the flag to a variable.
flag.IntVar(&num, "num", 25, "An integer value")
// Parse parses flag definitions from the argument list.
flag.Parse()
// Get the values from pointers
fmt.Println("filename:", *fileName)
fmt.Println("loglevel:", *logLevel)
fmt.Println("enable:", *isEnable)
// Get the value from a variable
fmt.Println("num:", num)
// Args returns the non-flag command-line arguments.
args := flag.Args()
if len(args) > 0 {
fmt.Println("The non-flag command-line arguments are:")
// Print the arguments
for _, v := range args {
fmt.Println(v)
}
}
}
================================================
FILE: ch05/flag/main.go
================================================
package main
import (
"flag"
"fmt"
)
func main() {
strPtr := flag.String("name", "Shiju", "a string")
numbPtr := flag.Int("num", 25, "an int")
boolPtr := flag.Bool("enable", false, "a bool")
var num int
flag.IntVar(&num, "num", 30, "an int")
// Parse parses flag definitions from the argument list.
flag.Parse()
// Get the values for pointers
fmt.Println("name:", *strPtr)
fmt.Println("num:", *numbPtr)
fmt.Println("enable:", *boolPtr)
// Get the value from a variable
fmt.Println("num:", num)
// Args returns the non-flag command-line arguments.
fmt.Println("arguments:", flag.Args())
}
================================================
FILE: ch05/json/main.go
================================================
package main
import (
"encoding/json"
"fmt"
)
// Employee struct
type Employee struct {
ID int
FirstName, LastName, JobTitle string
}
func main() {
emp := Employee{
ID: 100,
FirstName: "Shiju",
LastName: "Varghese",
JobTitle: "Architect",
}
// Encoding to JSON
data, err := json.Marshal(emp)
if err != nil {
fmt.Println(err.Error())
return
}
jsonStr := string(data)
fmt.Println("The JSON data is:")
fmt.Println(jsonStr)
b := []byte(`{"ID":101,"FirstName":"Irene","LastName":"Rose","JobTitle":"Developer"}`)
var emp1 Employee
// Decoding JSON data to a value of struct type
err = json.Unmarshal(b, &emp1)
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println("The Employee value is:")
fmt.Printf("ID:%d, Name:%s %s, JobTitle:%s", emp1.ID, emp1.FirstName, emp1.LastName, emp1.JobTitle)
}
================================================
FILE: ch05/jsontag/main.go
================================================
package main
import (
"encoding/json"
"fmt"
)
// Employee struct with struct tags
type Employee struct {
ID int `json:"id,omitempty"`
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
JobTitle string `json:"job"`
}
func main() {
emp := Employee{
FirstName: "Shiju",
LastName: "Varghese",
JobTitle: "Architect",
}
// Encoding to JSON
data, err := json.Marshal(emp)
if err != nil {
fmt.Println(err.Error())
return
}
jsonStr := string(data)
fmt.Println("The JSON data is:")
fmt.Println(jsonStr)
b := []byte(`{"id":101,"firstname":"Irene","lastname":"Rose","job":"Developer"}`)
var emp1 Employee
// Decoding JSON to a struct type
err = json.Unmarshal(b, &emp1)
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println("The Employee value is:")
fmt.Printf("ID:%d, Name:%s %s, JobTitle:%s", emp1.ID, emp1.FirstName, emp1.LastName, emp1.JobTitle)
}
================================================
FILE: ch05/log/logger.go
================================================
package main
import (
"io"
"io/ioutil"
"log"
"os"
)
const (
// UNSPECIFIED logs nothing
UNSPECIFIED Level = iota // 0 :
// TRACE logs everything
TRACE // 1
// INFO logs Info, Warnings and Errors
INFO // 2
// WARNING logs Warning and Errors
WARNING // 3
// ERROR just logs Errors
ERROR // 4
)
// Level holds the log level.
type Level int
// Package level variables, which are pointer to log.Logger.
var (
Trace *log.Logger
Info *log.Logger
Warning *log.Logger
Error *log.Logger
)
// initLog initializes log.Logger objects
func initLog(
traceHandle io.Writer,
infoHandle io.Writer,
warningHandle io.Writer,
errorHandle io.Writer,
isFlag bool) {
// Flags for defines the logging properties, to log.New
flag := 0
if isFlag {
flag = log.Ldate | log.Ltime | log.Lshortfile
}
// Create log.Logger objects.
Trace = log.New(traceHandle, "TRACE: ", flag)
Info = log.New(infoHandle, "INFO: ", flag)
Warning = log.New(warningHandle, "WARNING: ", flag)
Error = log.New(errorHandle, "ERROR: ", flag)
}
// SetLogLevel sets the logging level preference
func SetLogLevel(level Level) {
// Creates os.*File, which has implemented io.Writer intreface
f, err := os.OpenFile("logs.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("Error opening log file: %s", err.Error())
}
// Calls function initLog by specifying log level preference.
switch level {
case TRACE:
initLog(f, f, f, f, true)
return
case INFO:
initLog(ioutil.Discard, f, f, f, true)
return
case WARNING:
initLog(ioutil.Discard, ioutil.Discard, f, f, true)
return
case ERROR:
initLog(ioutil.Discard, ioutil.Discard, ioutil.Discard, f, true)
return
default:
initLog(ioutil.Discard, ioutil.Discard, ioutil.Discard, ioutil.Discard, false)
f.Close()
return
}
}
================================================
FILE: ch05/log/main.go
================================================
package main
import (
"errors"
"flag"
)
func main() {
// Parse log level from command line
logLevel := flag.Int("loglevel", 0, "an integer value (0-4)")
flag.Parse()
// Calling the SetLogLevel with the command-line argument
SetLogLevel(Level(*logLevel))
Trace.Println("Main started")
loop()
err := errors.New("Sample Error")
Error.Println(err.Error())
Trace.Println("Main completed")
}
// A simple function for the logging demo
func loop() {
Trace.Println("Loop started")
for i := 0; i < 10; i++ {
Info.Println("Counter value is:", i)
}
Warning.Println("The counter variable is not being used")
Trace.Println("Loop completed")
}
================================================
FILE: ch05/simplelog/main.go
================================================
package main
import (
"errors"
"io"
"io/ioutil"
"log"
"os"
)
// Package level variables, which are pointer to log.Logger.
var (
Trace *log.Logger
Info *log.Logger
Warning *log.Logger
Error *log.Logger
)
// initLog initializes log.Logger objects
func initLog(
traceHandle io.Writer,
infoHandle io.Writer,
warningHandle io.Writer,
errorHandle io.Writer) {
// Flags for defines the logging properties, to log.New
flag := log.Ldate | log.Ltime | log.Lshortfile
// Create log.Logger objects
Trace = log.New(traceHandle, "TRACE: ", flag)
Info = log.New(infoHandle, "INFO: ", flag)
Warning = log.New(warningHandle, "WARNING: ", flag)
Error = log.New(errorHandle, "ERROR: ", flag)
}
func main() {
initLog(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr)
Trace.Println("Main started")
loop()
err := errors.New("Sample Error")
Error.Println(err.Error())
Trace.Println("Main completed")
}
func loop() {
Trace.Println("Loop started")
for i := 0; i < 10; i++ {
Info.Println("Counter value is:", i)
}
Warning.Println("The counter variable is not being used")
Trace.Println("Loop completed")
}
================================================
FILE: ch06/influx/main.go
================================================
// Example demo for working with InfluxDB
package main
import (
"encoding/json"
"fmt"
"log"
"math/rand"
"time"
client "github.com/influxdata/influxdb/client/v2"
)
const (
// DB provides the database name of the InfluxDB
DB = "metricsdb"
username = "opsadmin"
password = "pass123"
)
func main() {
// Create client
c := influxDBClient()
// Write operations
// Create metrics data for measurement "cpu"
createMetrics(c)
// Read operations
// Read with limit of 10
readWithLimit(c, 10)
// Read mean value of "cpu_usage" for a region
meanCPUUsage(c, "us-west")
// Read count of records for a region
countRegion(c, "us-west")
}
// influxDBClient returns InfluxDB Client
func influxDBClient() client.Client {
c, err := client.NewHTTPClient(client.HTTPConfig{
Addr: "http://localhost:8086",
Username: username,
Password: password,
})
if err != nil {
log.Fatalln("Error: ", err)
}
return c
}
// createMetrics write batch points to create the metrics data
func createMetrics(clnt client.Client) {
batchCount := 100
rand.Seed(42)
// Create BatchPoints by giving config for InfluxDB
bp, _ := client.NewBatchPoints(client.BatchPointsConfig{
Database: DB,
Precision: "s",
})
// Batch update to adds Points
for i := 0; i < batchCount; i++ {
regions := []string{"us-west", "us-central", "us-north", "us-east"}
// tagset – “host” and “region”
tags := map[string]string{
"host": fmt.Sprintf("192.168.%d.%d", rand.Intn(100), rand.Intn(100)),
"region": regions[rand.Intn(len(regions))],
}
value := rand.Float64() * 100.0
// field - "cpu_usage"
fields := map[string]interface{}{
"cpu_usage": value,
}
pt, err := client.NewPoint("cpu", tags, fields, time.Now())
if err != nil {
log.Fatalln("Error: ", err)
}
// Add a Point
bp.AddPoint(pt)
}
// Writes the batch update to add points to measurement "cpu"
err := clnt.Write(bp)
if err != nil {
log.Fatalln("Error: ", err)
}
}
// queryDB query the database
func queryDB(clnt client.Client, command string) (res []client.Result, err error) {
// Create the query
q := client.Query{
Command: command,
Database: DB,
}
// Query the Database
if response, err := clnt.Query(q); err == nil {
if response.Error() != nil {
return res, response.Error()
}
res = response.Results
} else {
return res, err
}
return res, nil
}
// readWithLimit reads records with a given limit
func readWithLimit(clnt client.Client, limit int) {
q := fmt.Sprintf("SELECT * FROM %s LIMIT %d", "cpu", limit)
res, err := queryDB(clnt, q)
if err != nil {
log.Fatalln("Error: ", err)
}
for i, row := range res[0].Series[0].Values {
t, err := time.Parse(time.RFC3339, row[0].(string))
if err != nil {
log.Fatalln("Error: ", err)
}
val, err := row[1].(json.Number).Float64()
fmt.Printf("[%2d] %s: %f\n", i, t.Format(time.Stamp), val)
}
}
// meanCPUUsage reads the mean value of cpu_usage
func meanCPUUsage(clnt client.Client, region string) {
q := fmt.Sprintf("select mean(%s) from %s where region = '%s'", "cpu_usage", "cpu", region)
res, err := queryDB(clnt, q)
if err != nil {
log.Fatalln("Error: ", err)
}
value, err := res[0].Series[0].Values[0][1].(json.Number).Float64()
if err != nil {
log.Fatalln("Error: ", err)
}
fmt.Printf("Mean value of cpu_usage for region '%s':%f\n", region, value)
}
// countRegion reads the count of records for a given region
func countRegion(clnt client.Client, region string) {
q := fmt.Sprintf("SELECT count(%s) FROM %s where region = '%s'", "cpu_usage", "cpu", region)
res, err := queryDB(clnt, q)
if err != nil {
log.Fatalln("Error: ", err)
}
count := res[0].Series[0].Values[0][1]
fmt.Printf("Found a total of %v records for region '%s'\n", count, region)
}
================================================
FILE: ch06/mongo/bookmark_store.go
================================================
package main
import (
"time"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
// Bookmark type reperesents the metadata of a bookmark.
type Bookmark struct {
ID bson.ObjectId `bson:"_id,omitempty"`
Name, Description, Location string
Priority int // Priority (1 -5)
CreatedOn time.Time
Tags []string
}
// BookmarkStore provides CRUD operations against the collection "bookmarks".
type BookmarkStore struct {
C *mgo.Collection
}
// Create inserts the value of struct Bookmark into collection.
func (store BookmarkStore) Create(b *Bookmark) error {
// Assign a new bson.ObjectId
b.ID = bson.NewObjectId()
err := store.C.Insert(b)
return err
}
//Update modifies an existing value of a collection.
func (store BookmarkStore) Update(b Bookmark) error {
// partial update on MogoDB
err := store.C.Update(bson.M{"_id": b.ID},
bson.M{"$set": bson.M{
"name": b.Name,
"description": b.Description,
"location": b.Location,
"priority": b.Priority,
"tags": b.Tags,
}})
return err
}
// Delete removes an existing value from the collection.
func (store BookmarkStore) Delete(id string) error {
err := store.C.Remove(bson.M{"_id": bson.ObjectIdHex(id)})
return err
}
// GetAll returns all documents from the collection.
func (store BookmarkStore) GetAll() []Bookmark {
var b []Bookmark
iter := store.C.Find(nil).Sort("priority", "-createdon").Iter()
result := Bookmark{}
for iter.Next(&result) {
b = append(b, result)
}
return b
}
// GetByID returns single document from the collection.
func (store BookmarkStore) GetByID(id string) (Bookmark, error) {
var b Bookmark
err := store.C.FindId(bson.ObjectIdHex(id)).One(&b)
return b, err
}
// GetByTag returns all documents from the collection filtering by tags.
func (store BookmarkStore) GetByTag(tags []string) []Bookmark {
var b []Bookmark
iter := store.C.Find(bson.M{"tags": bson.M{"$in": tags}}).Sort("priority", "-createdon").Iter()
result := Bookmark{}
for iter.Next(&result) {
b = append(b, result)
}
return b
}
================================================
FILE: ch06/mongo/main.go
================================================
package main
import (
"fmt"
"log"
"time"
"gopkg.in/mgo.v2"
)
var store BookmarkStore
var id string
// init will invoke before the function main.
func init() {
session, err := mgo.DialWithInfo(&mgo.DialInfo{
Addrs: []string{"127.0.0.1"},
Timeout: 60 * time.Second,
})
if err != nil {
log.Fatalf("[MongoDB Session]: %s\n", err)
}
collection := session.DB("bookmarkdb").C("bookmarks")
collection.RemoveAll(nil)
store = BookmarkStore{
C: collection,
}
}
// Create and update documents.
func createUpdate() {
bookmark := Bookmark{
Name: "mgo",
Description: "Go driver for MongoDB",
Location: "https://github.com/go-mgo/mgo",
Priority: 2,
CreatedOn: time.Now(),
Tags: []string{"go", "nosql", "mongodb"},
}
// Insert a new document.
if err := store.Create(&bookmark); err != nil {
log.Fatalf("[Create]: %s\n", err)
}
id = bookmark.ID.Hex()
fmt.Printf("New bookmark has been inserted with ID: %s\n", id)
// Update an existing document.
bookmark.Priority = 1
if err := store.Update(bookmark); err != nil {
log.Fatalf("[Update]: %s\n", err)
}
fmt.Println("The value after update:")
// Retrieve the updated document.
getByID(id)
bookmark = Bookmark{
Name: "gorethink",
Description: "Go driver for RethinkDB",
Location: "https://github.com/dancannon/gorethink",
Priority: 3,
CreatedOn: time.Now(),
Tags: []string{"go", "nosql", "rethinkdb"},
}
// Insert a new document.
if err := store.Create(&bookmark); err != nil {
log.Fatalf("[Create]: %s\n", err)
}
id = bookmark.ID.Hex()
fmt.Printf("New bookmark has been inserted with ID: %s\n", id)
}
// Get a document by given id.
func getByID(id string) {
bookmark, err := store.GetByID(id)
if err != nil {
log.Fatalf("[GetByID]: %s\n", err)
}
fmt.Printf("Name:%s, Description:%s, Priority:%d\n",
bookmark.Name, bookmark.Description, bookmark.Priority)
}
// Get all documents from the collection.
func getAll() {
// Layout for formatting dates.
layout := "2006-01-02 15:04:05"
// Retrieve all documents.
bookmarks := store.GetAll()
fmt.Println("Read all documents")
for _, v := range bookmarks {
fmt.Printf("Name:%s, Description:%s, Priority:%d, CreatedOn:%s\n",
v.Name, v.Description, v.Priority, v.CreatedOn.Format(layout))
}
}
// Get documents by tags.
func getByTags() {
layout := "2006-01-02 15:04:05"
fmt.Println("Query with Tags - 'go, nosql'")
bookmarks := store.GetByTag([]string{"go", "nosql"})
for _, v := range bookmarks {
fmt.Printf("Name:%s, Description:%s, Priority:%d, CreatedOn:%s\n",
v.Name, v.Description, v.Priority, v.CreatedOn.Format(layout))
}
fmt.Println("Query with Tags - 'mongodb'")
bookmarks = store.GetByTag([]string{"mongodb"})
for _, v := range bookmarks {
fmt.Printf("Name:%s, Description:%s, Priority:%d, CreatedOn:%s\n",
v.Name, v.Description, v.Priority, v.CreatedOn.Format(layout))
}
}
// Delete an existing document from the collection.
func delete() {
if err := store.Delete(id); err != nil {
log.Fatalf("[Delete]: %s\n", err)
}
bookmarks := store.GetAll()
fmt.Printf("Number of documents in the collection after delete:%d\n", len(bookmarks))
}
// main - entry point of the program.
func main() {
createUpdate()
getAll()
getByTags()
delete()
}
================================================
FILE: ch06/postgres/main.go
================================================
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/lib/pq"
)
// Product struct provides the data model for productstore
type Product struct {
ID int
Title string
Description string
Price float32
}
var db *sql.DB
func init() {
var err error
db, err = sql.Open("postgres", "postgres://user:pass@localhost/productstore")
if err != nil {
log.Fatal(err)
}
}
func main() {
product := Product{
Title: "Amazon Echo",
Description: "Amazon Echo - Black",
Price: 179.99,
}
// Insert a product
createProduct(product)
// Read all product records
getProducts()
// Read a product by given id
getProductByID(1)
}
// createProduct inserts product values into product table
func createProduct(prd Product) {
result, err := db.Exec("INSERT INTO products(title, description, price) VALUES($1, $2, $3)", prd.Title, prd.Description, prd.Price)
if err != nil {
log.Fatal(err)
}
lastInsertID, err := result.LastInsertId()
rowsAffected, err := result.RowsAffected()
fmt.Printf("Product with id=%d created successfully (%d row affected)\n", lastInsertID, rowsAffected)
}
// getProducts reads all records from the product table
func getProducts() {
rows, err := db.Query("SELECT * FROM products")
if err != nil {
if err == sql.ErrNoRows {
fmt.Println("No Records Found")
return
}
log.Fatal(err)
}
defer rows.Close()
var products []*Product
for rows.Next() {
prd := &Product{}
err := rows.Scan(&prd.Title, &prd.Description, &prd.Price)
if err != nil {
log.Fatal(err)
}
products = append(products, prd)
}
if err = rows.Err(); err != nil {
log.Fatal(err)
}
for _, pr := range products {
fmt.Printf("%s, %s, $%.2f\n", pr.Title, pr.Description, pr.Price)
}
}
func getProductByID(id int) {
var product string
err := db.QueryRow("SELECT title FROM products WHERE id=$1", id).Scan(&product)
switch {
case err == sql.ErrNoRows:
log.Printf("No product with that ID.")
case err != nil:
log.Fatal(err)
default:
fmt.Printf("Product is %s\n", product)
}
}
================================================
FILE: ch06/rethink/bookmark_store.go
================================================
package main
import (
"time"
r "github.com/dancannon/gorethink"
)
// Bookmark type reperesents the metadata of a bookmark.
type Bookmark struct {
ID string `gorethink:"id,omitempty" json:"id"`
Name, Description, Location string
Priority int // Priority (1 -5)
CreatedOn time.Time
Tags []string
}
// BookmarkStore provides CRUD operations against the Table "bookmarks".
type BookmarkStore struct {
Session *r.Session
}
// Create inserts the value of struct Bookmark into Table.
func (store BookmarkStore) Create(b *Bookmark) error {
resp, err := r.Table("bookmarks").Insert(b).RunWrite(store.Session)
if err == nil {
b.ID = resp.GeneratedKeys[0]
}
return err
}
// Update modifies an existing value of a Table.
func (store BookmarkStore) Update(b Bookmark) error {
var data = map[string]interface{}{
"description": b.Description,
"location": b.Location,
"priority": b.Priority,
"tags": b.Tags,
}
// partial update on RethinkDB
_, err := r.Table("bookmarks").Get(b.ID).Update(data).RunWrite(store.Session)
return err
}
// Delete removes an existing value from the Table.
func (store BookmarkStore) Delete(id string) error {
_, err := r.Table("bookmarks").Get(id).Delete().RunWrite(store.Session)
return err
}
// GetAll returns all documents from the Table.
func (store BookmarkStore) GetAll() ([]Bookmark, error) {
bookmarks := []Bookmark{}
res, err := r.Table("bookmarks").OrderBy("priority", r.Desc("createdon")).Run(store.Session)
err = res.All(&bookmarks)
return bookmarks, err
}
// GetByID returns single document from the Table.
func (store BookmarkStore) GetByID(id string) (Bookmark, error) {
var b Bookmark
res, err := r.Table("bookmarks").Get(id).Run(store.Session)
res.One(&b)
return b, err
}
// // GetByTag returns all documents from the collection filtering by tags.
// func (store BookmarkStore) GetByTag(tags []string) ([]Bookmark, error) {
// bookmarks := []Bookmark{}
// res, err := r.Table("bookmarks").Filter(func(row r.Term) r.Term {
// return r.Expr(tags).Contains(row.Field("tags"))
// }).Run(store.Session)
// err = res.All(&bookmarks)
// return bookmarks, err
// }
================================================
FILE: ch06/rethink/main.go
================================================
package main
import (
"fmt"
"log"
"time"
r "github.com/dancannon/gorethink"
)
var store BookmarkStore
var id string
// initDB creates new database and
func initDB(session *r.Session) {
var err error
// Create Database
_, err = r.DBCreate("bookmarkdb").RunWrite(session)
if err != nil {
log.Fatalf("[initDB]: %s\n", err)
}
// Create Table
_, err = r.DB("bookmarkdb").TableCreate("bookmarks").RunWrite(session)
if err != nil {
log.Fatalf("[initDB]: %s\n", err)
}
}
// changeFeeds subscribes real-time updates on table bookmarks.
func changeFeeds(session *r.Session) {
bookmarks, err := r.Table("bookmarks").Changes().Field("new_val").Run(session)
if err != nil {
log.Fatalf("[changeFeeds]: %s\n", err)
}
// Luanch a goroutine to print real-time updates.
go func() {
var bookmark Bookmark
for bookmarks.Next(&bookmark) {
if bookmark.ID == "" { // for delete, new_val will be null.
fmt.Println("Real-time update: Document has been deleted")
} else {
fmt.Printf("Real-time update: Name:%s, Description:%s, Priority:%d\n",
bookmark.Name, bookmark.Description, bookmark.Priority)
}
}
}()
}
// init will invoke before the function main.
func init() {
session, err := r.Connect(r.ConnectOpts{
Address: "localhost:28015",
Database: "bookmarkdb",
MaxIdle: 10,
MaxOpen: 10,
})
if err != nil {
log.Fatalf("[RethinkDB Session]: %s\n", err)
}
r.Table("bookmarks").Delete().Run(session)
// Create Database and Table.
//initDB(session)
store = BookmarkStore{
Session: session,
}
// Subscribe real-time changes
changeFeeds(session)
}
// Create and update documents.
func createUpdate() {
bookmark := Bookmark{
Name: "mgo",
Description: "Go driver for MongoDB",
Location: "https://github.com/go-mgo/mgo",
Priority: 1,
CreatedOn: time.Now(),
Tags: []string{"go", "nosql", "mongodb"},
}
// Insert a new document.
if err := store.Create(&bookmark); err != nil {
log.Fatalf("[Create]: %s\n", err)
}
id = bookmark.ID
fmt.Printf("New bookmark has been inserted with ID: %s\n", id)
// Retrieve the updated document.
bookmark.Priority = 2
if err := store.Update(bookmark); err != nil {
log.Fatalf("[Update]: %s\n", err)
}
fmt.Println("The value after update:")
// Retrieve an existing document by id.
getByID(id)
bookmark = Bookmark{
Name: "gorethink",
Description: "Go driver for RethinkDB",
Location: "https://github.com/dancannon/gorethink",
Priority: 1,
CreatedOn: time.Now(),
Tags: []string{"go", "nosql", "rethinkdb"},
}
// Insert a new document.
if err := store.Create(&bookmark); err != nil {
log.Fatalf("[Create]: %s\n", err)
}
id = bookmark.ID
fmt.Printf("New bookmark has been inserted with ID: %s\n", id)
}
// Get a document by given id.
func getByID(id string) {
bookmark, err := store.GetByID(id)
if err != nil {
log.Fatalf("[GetByID]: %s\n", err)
}
fmt.Printf("Name:%s, Description:%s, Priority:%d\n", bookmark.Name, bookmark.Description, bookmark.Priority)
}
// Get all documents from bookmarks table.
func getAll() {
// Layout for formatting dates.
layout := "2006-01-02 15:04:05"
// Retrieve all documents.
bookmarks, err := store.GetAll()
if err != nil {
log.Fatalf("[GetAll]: %s\n", err)
}
fmt.Println("Read all documents")
for _, v := range bookmarks {
fmt.Printf("Name:%s, Description:%s, Priority:%d, CreatedOn:%s\n", v.Name, v.Description, v.Priority, v.CreatedOn.Format(layout))
}
}
// Delete an existing document from bookmarks table.
func delete() {
if err := store.Delete(id); err != nil {
log.Fatalf("[Delete]: %s\n", err)
}
bookmarks, err := store.GetAll()
if err != nil {
log.Fatalf("[GetAll]: %s\n", err)
}
fmt.Printf("Number of documents in the table after delete:%d\n", len(bookmarks))
}
// main - entry point of the program
func main() {
createUpdate()
getAll()
delete()
}
================================================
FILE: ch07/bookmarkapi/common/auth.go
================================================
package common
import (
"context"
"crypto/rsa"
"errors"
"io/ioutil"
"log"
"net/http"
"strings"
"time"
jwt "github.com/dgrijalva/jwt-go"
"github.com/dgrijalva/jwt-go/request"
)
// AppClaims provides custom claim for JWT
type AppClaims struct {
UserName string `json:"username"`
Role string `json:"role"`
jwt.StandardClaims
}
// using asymmetric crypto/RSA keys
// location of private/public key files
const (
// openssl genrsa -out app.rsa 1024
privKeyPath = "keys/app.rsa"
// openssl rsa -in app.rsa -pubout > app.rsa.pub
pubKeyPath = "keys/app.rsa.pub"
)
// Private key for signing and public key for verification
var (
//verifyKey, signKey []byte
verifyKey *rsa.PublicKey
signKey *rsa.PrivateKey
)
// Read the key files before starting http handlers
func initKeys() {
signBytes, err := ioutil.ReadFile(privKeyPath)
if err != nil {
log.Fatalf("[initKeys]: %s\n", err)
}
signKey, err = jwt.ParseRSAPrivateKeyFromPEM(signBytes)
if err != nil {
log.Fatalf("[initKeys]: %s\n", err)
}
verifyBytes, err := ioutil.ReadFile(pubKeyPath)
if err != nil {
log.Fatalf("[initKeys]: %s\n", err)
}
verifyKey, err = jwt.ParseRSAPublicKeyFromPEM(verifyBytes)
if err != nil {
log.Fatalf("[initKeys]: %s\n", err)
}
}
// GenerateJWT generates a new JWT token for authenticated user.
func GenerateJWT(name, role string) (string, error) {
// Create the Claims
claims := AppClaims{
UserName: name,
Role: role,
StandardClaims: jwt.StandardClaims{
ExpiresAt: time.Now().Add(time.Minute * 20).Unix(),
Issuer: "admin",
},
}
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
ss, err := token.SignedString(signKey)
if err != nil {
return "", err
}
return ss, nil
}
// AuthorizeRequest Middleware validates JWT tokens from incoming HTTP requests.
func AuthorizeRequest(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Get token from request
token, err := request.ParseFromRequestWithClaims(r, request.OAuth2Extractor, &AppClaims{}, func(token *jwt.Token) (interface{}, error) {
// since we only use the one private key to sign the tokens,
// we also only use its public counter part to verify
return verifyKey, nil
})
if err != nil {
switch err.(type) {
case *jwt.ValidationError: // JWT validation error
vErr := err.(*jwt.ValidationError)
switch vErr.Errors {
case jwt.ValidationErrorExpired: //JWT expired
DisplayAppError(
w,
err,
"Access Token is expired, get a new Token",
401,
)
return
default:
DisplayAppError(w,
err,
"Error while parsing the Access Token!",
500,
)
return
}
default:
DisplayAppError(w,
err,
"Error while parsing Access Token!",
500)
return
}
}
if token.Valid {
// Create a Context by setting the user name
ctx := context.WithValue(r.Context(), "user", token.Claims.(*AppClaims).UserName)
// Calls the next handler by providing the Context
next.ServeHTTP(w, r.WithContext(ctx))
} else {
DisplayAppError(
w,
err,
"Invalid Access Token",
401,
)
}
})
}
// AuthorizeRequestWithNegroni is a Negroni Middleware that validates JWT tokens
func AuthorizeRequestWithNegroni(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
// Get token from request
token, err := request.ParseFromRequestWithClaims(r, request.OAuth2Extractor, &AppClaims{}, func(token *jwt.Token) (interface{}, error) {
// since we only use the one private key to sign the tokens,
// we also only use its public counter part to verify
return verifyKey, nil
})
if err != nil {
switch err.(type) {
case *jwt.ValidationError: // JWT validation error
vErr := err.(*jwt.ValidationError)
switch vErr.Errors {
case jwt.ValidationErrorExpired: //JWT expired
DisplayAppError(
w,
err,
"Access Token is expired, get a new Token",
401,
)
return
default:
DisplayAppError(w,
err,
"Error while parsing the Access Token!",
500,
)
return
}
default:
DisplayAppError(w,
err,
"Error while parsing Access Token!",
500)
return
}
}
if token.Valid {
ctx := context.WithValue(r.Context(), "user", token.Claims.(*AppClaims).UserName)
next(w, r.WithContext(ctx))
} else {
DisplayAppError(
w,
err,
"Invalid Access Token",
401,
)
}
}
// TokenFromAuthHeader is a "TokenExtractor" that takes a given request and extracts
// the JWT token from the Authorization header.
func TokenFromAuthHeader(r *http.Request) (string, error) {
// Look for an Authorization header
if ah := r.Header.Get("Authorization"); ah != "" {
// Should be a bearer token
if len(ah) > 6 && strings.ToUpper(ah[0:6]) == "BEARER" {
return ah[7:], nil
}
}
return "", errors.New("No token in the HTTP request")
}
================================================
FILE: ch07/bookmarkapi/common/bootstrapper.go
================================================
package common
// StartUp bootstrapps the application
func StartUp() {
// Initialize AppConfig variable
initConfig()
// Initialize private/public keys for JWT authentication
initKeys()
// Initialize Logger objects with Log Level
setLogLevel(Level(AppConfig.LogLevel))
// Start a MongoDB session
createDBSession()
// Add indexes into MongoDB
addIndexes()
}
================================================
FILE: ch07/bookmarkapi/common/config.json
================================================
{
"Server" : "0.0.0.0:8080",
"MongoDBHost" : "127.0.0.1",
"MongoDBUser" : "",
"MongoDBPwd" : "",
"Database" : "bookmarkdb",
"LogLevel" : 4
}
================================================
FILE: ch07/bookmarkapi/common/logger.go
================================================
package common
import (
"io"
"io/ioutil"
"log"
"os"
)
const (
// UNSPECIFIED logs nothing
UNSPECIFIED Level = iota // 0 :
// TRACE logs everything
TRACE // 1
// INFO logs Info, Warnings and Errors
INFO // 2
// WARNING logs Warning and Errors
WARNING // 3
// ERROR just logs Errors
ERROR // 4
)
// Level holds the log level.
type Level int
// Package level variables, which are pointer to log.Logger.
var (
Trace *log.Logger
Info *log.Logger
Warning *log.Logger
Error *log.Logger
)
// initLog initializes log.Logger objects
func initLog(
traceHandle io.Writer,
infoHandle io.Writer,
warningHandle io.Writer,
errorHandle io.Writer,
isFlag bool) {
// Flags for defines the logging properties, to log.New
flag := 0
if isFlag {
flag = log.Ldate | log.Ltime | log.Lshortfile
}
// Create log.Logger objects.
Trace = log.New(traceHandle, "TRACE: ", flag)
Info = log.New(infoHandle, "INFO: ", flag)
Warning = log.New(warningHandle, "WARNING: ", flag)
Error = log.New(errorHandle, "ERROR: ", flag)
}
// SetLogLevel sets the logging level preference
func setLogLevel(level Level) {
// Creates os.*File, which has implemented io.Writer intreface
f, err := os.OpenFile("logs.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("Error opening log file: %s", err.Error())
}
// Calls function initLog by specifying log level preference.
switch level {
case TRACE:
initLog(f, f, f, f, true)
return
case INFO:
initLog(ioutil.Discard, f, f, f, true)
return
case WARNING:
initLog(ioutil.Discard, ioutil.Discard, f, f, true)
return
case ERROR:
initLog(ioutil.Discard, ioutil.Discard, ioutil.Discard, f, true)
return
default:
initLog(ioutil.Discard, ioutil.Discard, ioutil.Discard, ioutil.Discard, false)
f.Close()
return
}
}
================================================
FILE: ch07/bookmarkapi/common/mongo_utils.go
================================================
package common
import (
"log"
"time"
"gopkg.in/mgo.v2"
)
var session *mgo.Session
// GetSession returns a MongoDB Session
func getSession() *mgo.Session {
if session == nil {
var err error
session, err = mgo.DialWithInfo(&mgo.DialInfo{
Addrs: []string{AppConfig.MongoDBHost},
Username: AppConfig.DBUser,
Password: AppConfig.DBPwd,
Timeout: 60 * time.Second,
})
if err != nil {
log.Fatalf("[GetSession]: %s\n", err)
}
}
return session
}
func createDBSession() {
var err error
session, err = mgo.DialWithInfo(&mgo.DialInfo{
Addrs: []string{AppConfig.MongoDBHost},
Username: AppConfig.DBUser,
Password: AppConfig.DBPwd,
Timeout: 60 * time.Second,
})
if err != nil {
log.Fatalf("[createDbSession]: %s\n", err)
}
}
// Add indexes into MongoDB
func addIndexes() {
var err error
userIndex := mgo.Index{
Key: []string{"email"},
Unique: true,
Background: true,
Sparse: true,
}
// Add indexes into MongoDB
session := getSession().Copy()
defer session.Close()
userCol := session.DB(AppConfig.Database).C("users")
err = userCol.EnsureIndex(userIndex)
if err != nil {
log.Fatalf("[addIndexes]: %s\n", err)
}
}
// DataStore for MongoDB
type DataStore struct {
MongoSession *mgo.Session
}
// Close closes a mgo.Session value.
// Used to add defer statements for closing the copied session.
func (ds *DataStore) Close() {
ds.MongoSession.Close()
}
// Collection returns mgo.collection for the given name
func (ds *DataStore) Collection(name string) *mgo.Collection {
return ds.MongoSession.DB(AppConfig.Database).C(name)
}
// NewDataStore creates a new DataStore object to be used for each HTTP request.
func NewDataStore() *DataStore {
session := getSession().Copy()
dataStore := &DataStore{
MongoSession: session,
}
return dataStore
}
================================================
FILE: ch07/bookmarkapi/common/utils.go
================================================
package common
import (
"encoding/json"
"log"
"net/http"
"os"
)
type (
appError struct {
Error string `json:"error"`
Message string `json:"message"`
HTTPStatus int `json:"status"`
}
errorResource struct {
Data appError `json:"data"`
}
configuration struct {
Server, MongoDBHost, DBUser, DBPwd, Database string
LogLevel int
}
)
// DisplayAppError provides app specific error in JSON
func DisplayAppError(w http.ResponseWriter, handlerError error, message string, code int) {
errObj := appError{
Error: handlerError.Error(),
Message: message,
HTTPStatus: code,
}
//log.Printf("AppError]: %s\n", handlerError)
Error.Printf("AppError]: %s\n", handlerError)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(code)
if j, err := json.Marshal(errorResource{Data: errObj}); err == nil {
w.Write(j)
}
}
// AppConfig holds the configuration values from config.json file
var AppConfig configuration
// Initialize AppConfig
func initConfig() {
loadAppConfig()
}
// Reads config.json and decode into AppConfig
func loadAppConfig() {
file, err := os.Open("common/config.json")
defer file.Close()
if err != nil {
log.Fatalf("[loadConfig]: %s\n", err)
}
decoder := json.NewDecoder(file)
AppConfig = configuration{}
err = decoder.Decode(&AppConfig)
if err != nil {
log.Fatalf("[loadAppConfig]: %s\n", err)
}
}
================================================
FILE: ch07/bookmarkapi/controllers/bookmark_controller.go
================================================
package controllers
import (
"encoding/json"
"net/http"
"github.com/gorilla/mux"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"github.com/shijuvar/go-recipes/ch07/bookmarkapi/common"
"github.com/shijuvar/go-recipes/ch07/bookmarkapi/store"
)
// CreateBookmark insert a new Bookmark.
// Handler for HTTP Post - "/bookmarks
func CreateBookmark(w http.ResponseWriter, r *http.Request) {
var dataResource BookmarkResource
// Decode the incoming Bookmark json
err := json.NewDecoder(r.Body).Decode(&dataResource)
if err != nil {
common.DisplayAppError(
w,
err,
"Invalid Bookmark data",
500,
)
return
}
bookmark := &dataResource.Data
// Creates a new DatStore value to working with MongoDB store.
dataStore := common.NewDataStore()
// Add to the mgo.Session.Close()
defer dataStore.Close()
// Get the mgo.Collection for "bookmarks"
col := dataStore.Collection("bookmarks")
// Creates an instance of BookmarkStore
bookmarkStore := store.BookmarkStore{C: col}
// Takes user name from Context
user := r.Context().Value("user")
if user != nil {
bookmark.CreatedBy = user.(string)
}
// Insert a bookmark document
err = bookmarkStore.Create(bookmark)
if err != nil {
common.DisplayAppError(
w,
err,
"Invalid Bookmark data",
500,
)
return
}
j, err := json.Marshal(BookmarkResource{Data: *bookmark})
// If error is occured,
// Send JSON response using helper function common.DisplayAppError
if err != nil {
common.DisplayAppError(
w,
err,
"An unexpected error has occurred",
500,
)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
// Write the JSON data to the ResponseWriter
w.Write(j)
}
// GetBookmarks returns all Bookmark documents
// Handler for HTTP Get - "/Bookmarks"
func GetBookmarks(w http.ResponseWriter, r *http.Request) {
dataStore := common.NewDataStore()
defer dataStore.Close()
col := dataStore.Collection("bookmarks")
bookmarkStore := store.BookmarkStore{C: col}
bookmarks := bookmarkStore.GetAll()
j, err := json.Marshal(BookmarksResource{Data: bookmarks})
if err != nil {
common.DisplayAppError(
w,
err,
"An unexpected error has occurred",
500,
)
return
}
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
w.Write(j)
}
// GetBookmarkByID returns a single bookmark document by id
// Handler for HTTP Get - "/Bookmarks/{id}"
func GetBookmarkByID(w http.ResponseWriter, r *http.Request) {
// Get id from the incoming url
vars := mux.Vars(r)
id := vars["id"]
dataStore := common.NewDataStore()
defer dataStore.Close()
col := dataStore.Collection("bookmarks")
bookmarkStore := store.BookmarkStore{C: col}
bookmark, err := bookmarkStore.GetByID(id)
if err != nil {
if err == mgo.ErrNotFound {
w.WriteHeader(http.StatusNoContent)
} else {
common.DisplayAppError(
w,
err,
"An unexpected error has occurred",
500,
)
}
return
}
j, err := json.Marshal(bookmark)
if err != nil {
common.DisplayAppError(
w,
err,
"An unexpected error has occurred",
500,
)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(j)
}
// GetBookmarksByUser returns all Bookmarks created by a User
// Handler for HTTP Get - "/Bookmarks/users/{id}"
func GetBookmarksByUser(w http.ResponseWriter, r *http.Request) {
// Get id from the incoming url
vars := mux.Vars(r)
user := vars["id"]
dataStore := common.NewDataStore()
defer dataStore.Close()
col := dataStore.Collection("bookmarks")
bookmarkStore := store.BookmarkStore{C: col}
bookmarks := bookmarkStore.GetByUser(user)
j, err := json.Marshal(BookmarksResource{Data: bookmarks})
if err != nil {
common.DisplayAppError(
w,
err,
"An unexpected error has occurred",
500,
)
return
}
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
w.Write(j)
}
// UpdateBookmark update an existing Bookmark document
// Handler for HTTP Put - "/Bookmarks/{id}"
func UpdateBookmark(w http.ResponseWriter, r *http.Request) {
// Get id from the incoming url
vars := mux.Vars(r)
id := bson.ObjectIdHex(vars["id"])
var dataResource BookmarkResource
// Decode the incoming Bookmark json
err := json.NewDecoder(r.Body).Decode(&dataResource)
if err != nil {
common.DisplayAppError(
w,
err,
"Invalid Bookmark data",
500,
)
return
}
bookmark := dataResource.Data
bookmark.ID = id
dataStore := common.NewDataStore()
defer dataStore.Close()
col := dataStore.Collection("bookmarks")
bookmarkStore := store.BookmarkStore{C: col}
// Update an existing Bookmark document
if err := bookmarkStore.Update(bookmark); err != nil {
common.DisplayAppError(
w,
err,
"An unexpected error has occurred",
500,
)
return
}
w.WriteHeader(http.StatusNoContent)
}
// DeleteBookmark deletes an existing Bookmark document
// Handler for HTTP Delete - "/Bookmarks/{id}"
func DeleteBookmark(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id := vars["id"]
dataStore := common.NewDataStore()
defer dataStore.Close()
col := dataStore.Collection("bookmarks")
bookmarkStore := store.BookmarkStore{C: col}
// Delete an existing Bookmark document
err := bookmarkStore.Delete(id)
if err != nil {
common.DisplayAppError(
w,
err,
"An unexpected error has occurred",
500,
)
return
}
w.WriteHeader(http.StatusNoContent)
}
================================================
FILE: ch07/bookmarkapi/controllers/resources.go
================================================
package controllers
import (
"github.com/shijuvar/go-recipes/ch07/bookmarkapi/model"
)
//Models for JSON resources
type (
// UserResource For Post - /user/register
UserResource struct {
Data UserModel `json:"data"`
}
// AuthUserResource Response for authorized user Post - /user/login
AuthUserResource struct {
Data AuthUserModel `json:"data"`
}
// BookmarkResource For Post/Put - /bookmarks
// For Get - /bookmarks/id
BookmarkResource struct {
Data model.Bookmark `json:"data"`
}
// BookmarksResource for Get - /bookmarks
BookmarksResource struct {
Data []model.Bookmark `json:"data"`
}
// UserModel reperesents a user
UserModel struct {
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
Email string `json:"email"`
Password string `json:"password"`
}
// AuthUserModel for authorized user with access token
AuthUserModel struct {
User model.User `json:"user"`
Token string `json:"token"`
}
)
================================================
FILE: ch07/bookmarkapi/controllers/user_controller.go
================================================
package controllers
import (
"encoding/json"
"net/http"
"github.com/shijuvar/go-recipes/ch07/bookmarkapi/common"
"github.com/shijuvar/go-recipes/ch07/bookmarkapi/model"
"github.com/shijuvar/go-recipes/ch07/bookmarkapi/store"
)
// Register add a new User document
// Handler for HTTP Post - "/users/register"
func Register(w http.ResponseWriter, r *http.Request) {
var dataResource UserResource
// Decode the incoming User json
err := json.NewDecoder(r.Body).Decode(&dataResource)
if err != nil {
common.DisplayAppError(
w,
err,
"Invalid User data",
500,
)
return
}
userModel := dataResource.Data
dataStore := common.NewDataStore()
defer dataStore.Close()
col := dataStore.Collection("users")
userStore := store.UserStore{C: col}
user := model.User{
FirstName: userModel.FirstName,
LastName: userModel.LastName,
Email: userModel.Email,
}
// Insert User document
userStore.Create(user, userModel.Password)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
}
// Login authenticates the HTTP request with username and apssword
// Handler for HTTP Post - "/users/login"
func Login(w http.ResponseWriter, r *http.Request) {
var dataResource UserResource
var token string
// Decode the incoming Login json
err := json.NewDecoder(r.Body).Decode(&dataResource)
if err != nil {
common.DisplayAppError(
w,
err,
"Invalid Login data",
500,
)
return
}
loginUser := dataResource.Data
dataStore := common.NewDataStore()
defer dataStore.Close()
col := dataStore.Collection("users")
userStore := store.UserStore{C: col}
// Authenticate the login user
user, err := userStore.Login(loginUser.Email, loginUser.Password)
if err != nil {
common.DisplayAppError(
w,
err,
"Invalid login credentials",
401,
)
return
}
// Generate JWT token
token, err = common.GenerateJWT(user.Email, "member")
if err != nil {
common.DisplayAppError(
w,
err,
"Eror while generating the access token",
500,
)
return
}
w.Header().Set("Content-Type", "application/json")
// Clean-up the hashpassword to eliminate it from response JSON
user.HashPassword = nil
authUser := AuthUserModel{
User: user,
Token: token,
}
j, err := json.Marshal(AuthUserResource{Data: authUser})
if err != nil {
common.DisplayAppError(
w,
err,
"An unexpected error has occurred",
500,
)
return
}
w.WriteHeader(http.StatusOK)
w.Write(j)
}
================================================
FILE: ch07/bookmarkapi/keys/app.rsa
================================================
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQDPSMNALgfEMEDbS3kCLiTlpx0S4tZH1jZLcGF5Pjhc9IuEIf7p
6obYT1W7urDPWM8JGO1mdx+GnJCnPcvFSsX8FjGwDqIp7afTdislYCJwQLXL7qPz
wvG7ZlrtXrC9+0xkDGNxB+5Cui++8gWGbfTpTZiCiP413esxVQ30btKk2QIDAQAB
AoGACfj1M9RDGWQ86pAB/WHc8pOMqYjySDh9GjoI5n1g1tAJGk1MZ1KaNDP06vg7
Y25hX42sdj6K7L4Bk5o8gHxtc/IsheSeUFbdqbFdiAzTxgHq2zi1ZRPaxtNuw1Wk
KPxcehMpXl/eKCY50+bkVUTvBtfPjRat0fSZnQ4X24zHcAECQQDtU1S/Lu/7vfKI
BR9P2VoCfJvGuwpMcoaXcJuH9oEbeGKnSd7cKVeZdtuapHFjAm/yPWveOYmjrg6a
CiPIgWoBAkEA35hIN/f6wzpLiKPB1TERO/YH1qrRKoM17Y7qcqh8pjmfgY/8we6m
aGrFPd2eUVEpo5XMhQVpsluHmG8ZbXvK2QJAUlfueKM9ixg91WoJkjf03hYEKrDt
Atdd0Z+1pzglVbWwbSDZXYROq6WsznwuB09qLh+XlLRcCFm1IUdRYRleAQJAWQI9
FZKxD5CgSwetfNnom28IlcswMvVCvYvcBsLNxDpCJgiUvPrs4bpHRKZ5hLODmOxk
GzwZZHgNVYA8phnWmQJAER8blPRwsHaEUdPLKWPffvlGPh8RJwpWtaneBOhkyylh
HbPOBvC2WGJ7uXYTiXPHwOeLyRtUYx2GaoKQImi3sw==
-----END RSA PRIVATE KEY-----
================================================
FILE: ch07/bookmarkapi/keys/app.rsa.pub
================================================
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPSMNALgfEMEDbS3kCLiTlpx0S
4tZH1jZLcGF5Pjhc9IuEIf7p6obYT1W7urDPWM8JGO1mdx+GnJCnPcvFSsX8FjGw
DqIp7afTdislYCJwQLXL7qPzwvG7ZlrtXrC9+0xkDGNxB+5Cui++8gWGbfTpTZiC
iP413esxVQ30btKk2QIDAQAB
-----END PUBLIC KEY-----
================================================
FILE: ch07/bookmarkapi/main.go
================================================
package main
import (
"log"
"net/http"
"github.com/shijuvar/go-recipes/ch07/bookmarkapi/common"
"github.com/shijuvar/go-recipes/ch07/bookmarkapi/routers"
)
// Entry point of the program
func main() {
// Calls startup logic
common.StartUp()
// Get the mux router object
router := routers.InitRoutes()
// Create the Server
server := &http.Server{
Addr: common.AppConfig.Server,
Handler: router,
}
log.Println("Listening...")
// Running the HTTP Server
server.ListenAndServe()
}
================================================
FILE: ch07/bookmarkapi/model/models.go
================================================
package model
import (
"time"
"gopkg.in/mgo.v2/bson"
)
type (
// User type represents the registered user.
User struct {
ID bson.ObjectId `bson:"_id,omitempty" json:"id"`
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
Email string `json:"email"`
HashPassword []byte `json:"hashpassword,omitempty"`
}
// Bookmark type represents the metadata of a bookmark.
Bookmark struct {
ID bson.ObjectId `bson:"_id,omitempty"`
Name string `json:"name"`
Description string `json:"description"`
Location string `json:"location"`
Priority int `json:"priority"` // Priority (1 -5)
CreatedBy string `json:"createdby"`
CreatedOn time.Time `json:"createdon,omitempty"`
Tags []string `json:"tags,omitempty"`
}
)
================================================
FILE: ch07/bookmarkapi/routers/bookmark.go
================================================
package routers
import (
"github.com/gorilla/mux"
"github.com/shijuvar/go-recipes/ch07/bookmarkapi/common"
"github.com/shijuvar/go-recipes/ch07/bookmarkapi/controllers"
)
// SetBookmarkRoutes registers routes for bookmark entity.
func SetBookmarkRoutes(router *mux.Router) *mux.Router {
bookmarkRouter := mux.NewRouter()
bookmarkRouter.HandleFunc("/bookmarks", controllers.CreateBookmark).Methods("POST")
bookmarkRouter.HandleFunc("/bookmarks/{id}", controllers.UpdateBookmark).Methods("PUT")
bookmarkRouter.HandleFunc("/bookmarks", controllers.GetBookmarks).Methods("GET")
bookmarkRouter.HandleFunc("/bookmarks/{id}", controllers.GetBookmarkByID).Methods("GET")
bookmarkRouter.HandleFunc("/bookmarks/users/{id}", controllers.GetBookmarksByUser).Methods("GET")
bookmarkRouter.HandleFunc("/bookmarks/{id}", controllers.DeleteBookmark).Methods("DELETE")
router.PathPrefix("/bookmarks").Handler(common.AuthorizeRequest(bookmarkRouter))
return router
}
================================================
FILE: ch07/bookmarkapi/routers/routers.go
================================================
package routers
import (
"github.com/gorilla/mux"
)
// InitRoutes registers all routes for the application.
func InitRoutes() *mux.Router {
router := mux.NewRouter().StrictSlash(false)
// Routes for the User entity
router = SetUserRoutes(router)
// Routes for the Bookmark entity
router = SetBookmarkRoutes(router)
return router
}
================================================
FILE: ch07/bookmarkapi/routers/user.go
================================================
package routers
import (
"github.com/shijuvar/go-recipes/ch07/bookmarkapi/controllers"
"github.com/gorilla/mux"
)
// SetUserRoutes registers routes for user entity
func SetUserRoutes(router *mux.Router) *mux.Router {
router.HandleFunc("/users", controllers.Register).Methods("POST")
router.HandleFunc("/users/login", controllers.Login).Methods("POST")
return router
}
================================================
FILE: ch07/bookmarkapi/store/bookmark_store.go
================================================
package store
import (
"time"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"github.com/shijuvar/go-recipes/ch07/bookmarkapi/model"
)
// BookmarkStore provides CRUD operations against the collection "bookmarks".
type BookmarkStore struct {
C *mgo.Collection
}
// Create inserts the value of struct Bookmark into collection.
func (store BookmarkStore) Create(b *model.Bookmark) error {
// Assign a new bson.ObjectId
b.ID = bson.NewObjectId()
b.CreatedOn = time.Now()
err := store.C.Insert(b)
return err
}
// Update modifies an existing document of a collection.
func (store BookmarkStore) Update(b model.Bookmark) error {
// partial update on MogoDB
err := store.C.Update(bson.M{"_id": b.ID},
bson.M{"$set": bson.M{
"name": b.Name,
"description": b.Description,
"location": b.Location,
"priority": b.Priority,
"tags": b.Tags,
}})
return err
}
// Delete removes an existing document from the collection.
func (store BookmarkStore) Delete(id string) error {
err := store.C.Remove(bson.M{"_id": bson.ObjectIdHex(id)})
return err
}
// GetAll returns all documents from the collection.
func (store BookmarkStore) GetAll() []model.Bookmark {
var b []model.Bookmark
iter := store.C.Find(nil).Sort("priority", "-createdon").Iter()
result := model.Bookmark{}
for iter.Next(&result) {
b = append(b, result)
}
return b
}
// GetByUser returns all documents from the collection.
func (store BookmarkStore) GetByUser(user string) []model.Bookmark {
var b []model.Bookmark
iter := store.C.Find(bson.M{"createdby": user}).Sort("priority", "-createdon").Iter()
result := model.Bookmark{}
for iter.Next(&result) {
b = append(b, result)
}
return b
}
// GetByID returns a single document from the collection.
func (store BookmarkStore) GetByID(id string) (model.Bookmark, error) {
var b model.Bookmark
err := store.C.FindId(bson.ObjectIdHex(id)).One(&b)
return b, err
}
// GetByTag returns all documents from the collection filtering by tags.
func (store BookmarkStore) GetByTag(tags []string) []model.Bookmark {
var b []model.Bookmark
iter := store.C.Find(bson.M{"tags": bson.M{"$in": tags}}).Sort("priority", "-createdon").Iter()
result := model.Bookmark{}
for iter.Next(&result) {
b = append(b, result)
}
return b
}
================================================
FILE: ch07/bookmarkapi/store/user_store.go
================================================
package store
import (
"golang.org/x/crypto/bcrypt"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"github.com/shijuvar/go-recipes/ch07/bookmarkapi/model"
)
// UserStore provides persistence logic for "users" collection.
type UserStore struct {
C *mgo.Collection
}
// Create insert new User
func (store UserStore) Create(user model.User, password string) error {
user.ID = bson.NewObjectId()
hpass, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return err
}
user.HashPassword = hpass
err = store.C.Insert(user)
return err
}
// Login authenticates the User
func (store UserStore) Login(email, password string) (model.User, error) {
var user model.User
err := store.C.Find(bson.M{"email": email}).One(&user)
if err != nil {
return model.User{}, err
}
// Validate password
err = bcrypt.CompareHashAndPassword(user.HashPassword, []byte(password))
if err != nil {
return model.User{}, err
}
return user, nil
}
================================================
FILE: ch07/customhandler/main.go
================================================
package main
import (
"fmt"
"log"
"net/http"
)
type textHandler struct {
responseText string
}
func (th *textHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, th.responseText)
}
type indexHandler struct {
}
func (ih *indexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set(
"Content-Type",
"text/html",
)
html :=
`<doctype html>
<html>
<head>
<title>Hello Gopher</title>
</head>
<body>
<b>Hello Gopher!</b>
<p>
<a href="/welcome">Welcome</a> | <a href="/message">Message</a>
</p>
</body>
</html>`
fmt.Fprintf(w, html)
}
func main() {
mux := http.NewServeMux()
mux.Handle("/", &indexHandler{})
thWelcome := &textHandler{"Welcome to Go Web Programming"}
mux.Handle("/welcome", thWelcome)
thMessage := &textHandler{"net/http package is used to build web apps"}
mux.Handle("/message", thMessage)
log.Println("Listening...")
http.ListenAndServe(":8080", mux)
}
================================================
FILE: ch07/defaultservemux/main.go
================================================
package main
import (
"fmt"
"log"
"net/http"
)
func index(w http.ResponseWriter, r *http.Request) {
w.Header().Set(
"Content-Type",
"text/html",
)
html :=
`<doctype html>
<html>
<head>
<title>Hello Gopher</title>
</head>
<body>
<b>Hello Gopher!</b>
<p>
<a href="/welcome">Welcome</a> | <a href="/message">Message</a>
</p>
</body>
</html>`
fmt.Fprintf(w, html)
}
func welcome(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Welcome to Go Web Programming")
}
func message(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "net/http package is used to build web apps")
}
func main() {
http.HandleFunc("/", index)
http.HandleFunc("/welcome", welcome)
http.HandleFunc("/message", message)
log.Println("Listening...")
http.ListenAndServe(":8080", nil)
}
================================================
FILE: ch07/handlefunc/main.go
================================================
package main
import (
"fmt"
"log"
"net/http"
)
func index(w http.ResponseWriter, r *http.Request) {
w.Header().Set(
"Content-Type",
"text/html",
)
html :=
`<doctype html>
<html>
<head>
<title>Hello Gopher</title>
</head>
<body>
<b>Hello Gopher!</b>
<p>
<a href="/welcome">Welcome</a> | <a href="/message">Message</a>
</p>
</body>
</html>`
fmt.Fprintf(w, html)
}
func welcome(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Welcome to Go Web Programming")
}
func message(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "net/http package is used to build web apps")
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", index)
mux.HandleFunc("/welcome", welcome)
mux.HandleFunc("/message", message)
log.Println("Listening...")
http.ListenAndServe(":8080", mux)
}
================================================
FILE: ch07/handlerfunc/main.go
================================================
package main
import (
"fmt"
"log"
"net/http"
)
func textResponseHandler(resposeText string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, resposeText)
})
}
func index(w http.ResponseWriter, r *http.Request) {
w.Header().Set(
"Content-Type",
"text/html",
)
html :=
`<doctype html>
<html>
<head>
<title>Hello Gopher</title>
</head>
<body>
<b>Hello Gopher!</b>
<p>
<a href="/welcome">Welcome</a> | <a href="/message">Message</a>
</p>
</body>
</html>`
fmt.Fprintf(w, html)
}
func welcome(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Welcome to Go Web Programming")
}
func message(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "net/http package is used to build web apps")
}
func main() {
mux := http.NewServeMux()
mux.Handle("/", http.HandlerFunc(index))
mux.Handle("/welcome", http.HandlerFunc(welcome))
mux.Handle("/message", http.HandlerFunc(message))
//mux.Handle("/welcome", textResponseHandler("Welcome to Go Web Programming"))
//mux.Handle("/message", textResponseHandler("net/http package is used to build web apps"))
log.Println("Listening...")
http.ListenAndServe(":8080", mux)
}
================================================
FILE: ch07/httpserver/main.go
================================================
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello, world!")
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
================================================
FILE: ch07/middleware/main.go
================================================
package main
import (
"fmt"
"log"
"net/http"
"time"
)
// loggingHandler is an HTTP Middleware that logs HTTP requests.
func loggingHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Middleware logic before executing given Handler
start := time.Now()
log.Printf("Started %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
// Middleware logic after executing given Handler
log.Printf("Completed %s in %v", r.URL.Path, time.Since(start))
})
}
func index(w http.ResponseWriter, r *http.Request) {
w.Header().Set(
"Content-Type",
"text/html",
)
html :=
`<doctype html>
<html>
<head>
<title>Hello Gopher</title>
</head>
<body>
<b>Hello Gopher!</b>
<p>
<a href="/welcome">Welcome</a> | <a href="/message">Message</a>
</p>
</body>
</html>`
fmt.Fprintf(w, html)
}
func welcome(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Welcome to Go Web Programming")
}
func message(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "net/http package is used to build web apps")
}
func favicon(w http.ResponseWriter, r *http.Request) {
}
func main() {
http.HandleFunc("/favicon.ico", favicon)
http.Handle("/", loggingHandler(http.HandlerFunc(index)))
http.Handle("/welcome", loggingHandler(http.HandlerFunc(welcome)))
http.Handle("/message", loggingHandler(http.HandlerFunc(message)))
log.Println("Listening...")
http.ListenAndServe(":8080", nil)
}
================================================
FILE: ch07/server/main.go
================================================
package main
import (
"fmt"
"log"
"net/http"
"time"
)
func index(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Welcome to Go Web Programming")
}
func main() {
http.HandleFunc("/", index)
server := &http.Server{
Addr: ":8080",
ReadTimeout: 60 * time.Second,
WriteTimeout: 60 * time.Second,
}
log.Println("Listening...")
server.ListenAndServe()
}
================================================
FILE: ch08/calc/calc.go
================================================
// Package calc provides a simple calculator
package calc
import "math"
// Sum returns sum of integer values
func Sum(nums ...int) int {
result := 0
for _, v := range nums {
result += v
}
return result
}
// Average returns average of integer values
// The output provides a float64 value in two decimal points
func Average(nums ...int) float64 {
sum := 0
for _, v := range nums {
sum += v
}
result := float64(sum) / float64(len(nums))
pow := math.Pow(10, float64(2))
digit := pow * result
round := math.Floor(digit)
return round / pow
}
================================================
FILE: ch08/calc/calc_test.go
================================================
package calc
import (
"fmt"
"testing"
"time"
)
// Test case for the function Sum
func TestSum(t *testing.T) {
input, expected := []int{7, 8, 10}, 25
result := Sum(input...)
if result != expected {
t.Errorf("Result: %d, Expected: %d", result, expected)
}
}
// Test case for function Average
func TestAverage(t *testing.T) {
input, expected := []int{7, 8, 10}, 8.33
result := Average(input...)
if result != expected {
t.Errorf("Result: %f, Expected: %f", result, expected)
}
}
// Benchmark for function Sum
func BenchmarkSum(b *testing.B) {
for i := 0; i < b.N; i++ {
Sum(7, 8, 10)
}
}
// Benchmark for function Average
func BenchmarkAverage(b *testing.B) {
for i := 0; i < b.N; i++ {
Average(7, 8, 10)
}
}
func TestLongRun(t *testing.T) {
// Checks whether the short flag is provided
if testing.Short() {
t.Skip("Skipping test in short mode")
}
// Long running implementation goes here
time.Sleep(5 * time.Second)
}
// Test case for the function Sum to be executed in parallel
func TestSumInParallel(t *testing.T) {
t.Parallel()
// Delaying 1 second for the sake of demonstration
time.Sleep(1 * time.Second)
input, expected := []int{7, 8, 10}, 25
result := Sum(input...)
if result != expected {
t.Errorf("Result: %d, Expected: %d", result, expected)
}
}
// Test case for the function Sum to be executed in parallel
func TestAverageInParallel(t *testing.T) {
t.Parallel()
// Delaying 1 second for the sake of demonstration
time.Sleep(2 * time.Second)
input, expected := []int{7, 8, 10}, 8.33
result := Average(input...)
if result != expected {
t.Errorf("Result: %f, Expected: %f", result, expected)
}
}
// Example code for function Sum
func ExampleSum() {
fmt.Println(Sum(7, 8, 10))
// Output: 25
}
// Example code for function Average
func ExampleAverage() {
fmt.Println(Average(7, 8, 10))
// Output: 8.33
}
================================================
FILE: ch08/httpbdd/controllers/controllers_suite_test.go
================================================
package controllers_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing"
)
func TestControllers(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Controllers Suite")
}
================================================
FILE: ch08/httpbdd/controllers/user_controller.go
================================================
package controllers
import (
"encoding/json"
"log"
"net/http"
"github.com/shijuvar/go-recipes/ch08/httpbdd/model"
)
// GetUsers serves requests for Http Get to "/users"
func GetUsers(store model.UserStore) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
data := store.GetUsers()
users, err := json.Marshal(data)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(users)
})
}
// CreateUser serves requests for Http Post to "/users"
func CreateUser(store model.UserStore) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var user model.User
// Decode the incoming User json
err := json.NewDecoder(r.Body).Decode(&user)
if err != nil {
log.Fatalf("[Controllers.CreateUser]: %s\n", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
// Insert User entity into User Store
err = store.AddUser(user)
if err != nil {
if err == model.ErrorEmailExists {
w.WriteHeader(http.StatusBadRequest)
} else {
w.WriteHeader(http.StatusInternalServerError)
}
return
}
w.WriteHeader(http.StatusCreated)
})
}
================================================
FILE: ch08/httpbdd/controllers/user_controller_test.go
================================================
package controllers_test
import (
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"github.com/shijuvar/go-recipes/ch08/httpbdd/controllers"
"github.com/shijuvar/go-recipes/ch08/httpbdd/model"
"github.com/gorilla/mux"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("UserController", func() {
var r *mux.Router
var w *httptest.ResponseRecorder
var store *FakeUserStore
BeforeEach(func() {
r = mux.NewRouter()
store = newFakeUserStore()
})
// Specs for HTTP Get to "/users"
Describe("Get list of Users", func() {
Context("Get all Users from data store", func() {
It("Should get list of Users", func() {
r.Handle("/users", controllers.GetUsers(store)).Methods("GET")
req, err := http.NewRequest("GET", "/users", nil)
Expect(err).NotTo(HaveOccurred())
w = httptest.NewRecorder()
r.ServeHTTP(w, req)
Expect(w.Code).To(Equal(200))
var users []model.User
json.Unmarshal(w.Body.Bytes(), &users)
// Verifying mocked data of 2 users
Expect(len(users)).To(Equal(2))
})
})
})
// Specs for HTTP Post to "/users"
Describe("Post a new User", func() {
Context("Provide a valid User data", func() {
It("Should create a new User and get HTTP Status: 201", func() {
r.Handle("/users", controllers.CreateUser(store)).Methods("POST")
userJson := `{"firstname": "Alex", "lastname": "John", "email": "alex@xyz.com"}`
req, err := http.NewRequest(
"POST",
"/users",
strings.NewReader(userJson),
)
Expect(err).NotTo(HaveOccurred())
w = httptest.NewRecorder()
r.ServeHTTP(w, req)
Expect(w.Code).To(Equal(201))
})
})
Context("Provide a User data that contains duplicate email id", func() {
It("Should get HTTP Status: 400", func() {
r.Handle("/users", controllers.CreateUser(store)).Methods("POST")
userJson := `{"firstname": "Shiju", "lastname": "Varghese", "email": "shiju@xyz.com"}`
req, err := http.NewRequest(
"POST",
"/users",
strings.NewReader(userJson),
)
Expect(err).NotTo(HaveOccurred())
w = httptest.NewRecorder()
r.ServeHTTP(w, req)
Expect(w.Code).To(Equal(400))
})
})
})
})
// FakeUserStore provides a mocked implementation of interface model.UserStore
type FakeUserStore struct {
userStore []model.User
}
// GetUsers returns all users
func (store *FakeUserStore) GetUsers() []model.User {
return store.userStore
}
// AddUser inserts a User
func (store *FakeUserStore) AddUser(user model.User) error {
// Check whether email is exists
for _, u := range store.userStore {
if u.Email == user.Email {
return model.ErrorEmailExists
}
}
store.userStore = append(store.userStore, user)
return nil
}
// newFakeUserStore provides two dummy data for Users
func newFakeUserStore() *FakeUserStore {
store := &FakeUserStore{}
store.AddUser(model.User{
FirstName: "Shiju",
LastName: "Varghese",
Email: "shiju@xyz.com",
})
store.AddUser(model.User{
FirstName: "Irene",
LastName: "Rose",
Email: "irene@xyz.com",
})
return store
}
================================================
FILE: ch08/httpbdd/main.go
================================================
package main
import (
"net/http"
"github.com/gorilla/mux"
"github.com/shijuvar/go-recipes/ch08/httpbdd/controllers"
"github.com/shijuvar/go-recipes/ch08/httpbdd/store"
)
func setUserRoutes() *mux.Router {
r := mux.NewRouter()
userStore := &store.MongoUserStore{}
r.Handle("/users", controllers.CreateUser(userStore)).Methods("POST")
r.Handle("/users", controllers.GetUsers(userStore)).Methods("GET")
return r
}
func main() {
http.ListenAndServe(":8080", setUserRoutes())
}
================================================
FILE: ch08/httpbdd/model/user.go
================================================
package model
import "errors"
// ErrorEmailExists is an error value for duplicate email id
var ErrorEmailExists = errors.New("Email Id is exists")
// User model
type User struct {
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
Email string `json:"email"`
}
// UserStore provides a contract for Data Store for User entity
type UserStore interface {
GetUsers() []User
AddUser(User) error
}
================================================
FILE: ch08/httpbdd/store/user_store.go
================================================
package store
import (
"log"
"time"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"github.com/shijuvar/go-recipes/ch08/httpbdd/model"
)
// MongoDB Session
var mgoSession *mgo.Session
// Create a MongoDB Session
func createDBSession() {
var err error
mgoSession, err = mgo.DialWithInfo(&mgo.DialInfo{
Addrs: []string{"127.0.0.1"},
Timeout: 60 * time.Second,
})
if err != nil {
log.Fatalf("[createDbSession]: %s\n", err)
}
}
// Initializes the MongoDB Session
func init() {
createDBSession()
}
// MongoUserStore provides persistence logic for "users" collection.
type MongoUserStore struct{}
// AddUser insert new User
func (store *MongoUserStore) AddUser(user model.User) error {
session := mgoSession.Copy()
defer session.Close()
userCol := session.DB("userdb").C("users")
// Check whether email id is exists or not
var existUser model.User
err := userCol.Find(bson.M{"email": user.Email}).One(&existUser)
if err != nil {
if err == mgo.ErrNotFound { // Email is unique, no records found
}
}
if (model.User{}) != existUser { // there is a user
return model.ErrorEmailExists
}
err = userCol.Insert(user)
return err
}
// GetUsers returns all documents from the collection.
func (store *MongoUserStore) GetUsers() []model.User {
session := mgoSession.Copy()
defer session.Close()
userCol := session.DB("userdb").C("users")
var users []model.User
iter := userCol.Find(nil).Iter()
result := model.User{}
for iter.Next(&result) {
users = append(users, result)
}
return users
}
================================================
FILE: ch08/httptest/main.go
================================================
package main
import (
"encoding/json"
"net/http"
"github.com/gorilla/mux"
)
// User model
type User struct {
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
Email string `json:"email"`
}
// getUsers serves requests for Http Get to "/users"
func getUsers(w http.ResponseWriter, r *http.Request) {
data := []User{
User{
FirstName: "Shiju",
LastName: "Varghese",
Email: "shiju@xyz.com",
},
User{
FirstName: "Irene",
LastName: "Rose",
Email: "irene@xyz.com",
},
}
users, err := json.Marshal(data)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(users)
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/users", getUsers).Methods("GET")
http.ListenAndServe(":8080", r)
}
================================================
FILE: ch08/httptest/main_test.go
================================================
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/gorilla/mux"
)
// TestGetUsers test HTTP Get to "/users" using ResponseRecorder
func TestGetUsers(t *testing.T) {
r := mux.NewRouter()
r.HandleFunc("/users", getUsers).Methods("GET")
req, err := http.NewRequest("GET", "/users", nil)
if err != nil {
t.Error(err)
}
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
if w.Code != 200 {
t.Errorf("HTTP Status expected: 200, got: %d", w.Code)
}
}
// TestGetUsersWithServer test HTTP Get to "/users" using Server
func TestGetUsersWithServer(t *testing.T) {
r := mux.NewRouter()
r.HandleFunc("/users", getUsers).Methods("GET")
server := httptest.NewServer(r)
defer server.Close()
usersURL := fmt.Sprintf("%s/users", server.URL)
request, err := http.NewRequest("GET", usersURL, nil)
res, err := http.DefaultClient.Do(request)
if err != nil {
t.Error(err)
}
if res.StatusCode != 200 {
t.Errorf("HTTP Status expected: 200, got: %d", res.StatusCode)
}
}
================================================
FILE: grpc/client/main.go
================================================
package main
import (
"io"
"log"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "github.com/shijuvar/go-recipes/grpc/customer"
)
const (
address = "localhost:50051"
)
// createCustomer calls the RPC method CreateCustomer of CustomerServer
func createCustomer(client pb.CustomerClient, customer *pb.CustomerRequest) {
resp, err := client.CreateCustomer(context.Background(), customer)
if err != nil {
log.Fatalf("Could not create Customer: %v", err)
}
if resp.Success {
log.Printf("A new Customer has been added with id: %d", resp.Id)
}
}
// getCustomers calls the RPC method GetCustomers of CustomerServer
func getCustomers(client pb.CustomerClient, filter *pb.CustomerFilter) {
// calling the streaming API
stream, err := client.GetCustomers(context.Background(), filter)
if err != nil {
log.Fatalf("Error on get customers: %v", err)
}
for {
// Receiving the stream of data
customer, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("%v.GetCustomers(_) = _, %v", client, err)
}
log.Printf("Customer: %v", customer)
}
}
func main() {
// Set up a connection to the gRPC server.
conn, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
// Creates a new CustomerClient
client := pb.NewCustomerClient(conn)
customer := &pb.CustomerRequest{
Id: 101,
Name: "Shiju Varghese",
Email: "shiju@xyz.com",
Phone: "732-757-2923",
Addresses: []*pb.CustomerRequest_Address{
&pb.CustomerRequest_Address{
Street: "1 Mission Street",
City: "San Francisco",
State: "CA",
Zip: "94105",
IsShippingAddress: false,
},
&pb.CustomerRequest_Address{
Street: "Greenfield",
City: "Kochi",
State: "KL",
Zip: "68356",
IsShippingAddress: true,
},
},
}
// Create a new customer
createCustomer(client, customer)
customer = &pb.CustomerRequest{
Id: 102,
Name: "Irene Rose",
Email: "irene@xyz.com",
Phone: "732-757-2924",
Addresses: []*pb.CustomerRequest_Address{
&pb.CustomerRequest_Address{
Street: "1 Mission Street",
City: "San Francisco",
State: "CA",
Zip: "94105",
IsShippingAddress: true,
},
},
}
// Create a new customer
createCustomer(client, customer)
// Filter with an empty Keyword
filter := &pb.CustomerFilter{Keyword: ""}
getCustomers(client, filter)
}
================================================
FILE: grpc/customer/customer.pb.go
================================================
// Code generated by protoc-gen-go.
// source: customer.proto
// DO NOT EDIT!
/*
Package customer is a generated protocol buffer package.
It is generated from these files:
customer.proto
It has these top-level messages:
CustomerRequest
CustomerResponse
CustomerFilter
*/
package customer
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// Request message for creating a new customer
type CustomerRequest struct {
Id int32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"`
Email string `protobuf:"bytes,3,opt,name=email" json:"email,omitempty"`
Phone string `protobuf:"bytes,4,opt,name=phone" json:"phone,omitempty"`
Addresses []*CustomerRequest_Address `protobuf:"bytes,5,rep,name=addresses" json:"addresses,omitempty"`
}
func (m *CustomerRequest) Reset() { *m = CustomerRequest{} }
func (m *CustomerRequest) String() string { return proto.CompactTextString(m) }
func (*CustomerRequest) ProtoMessage() {}
func (*CustomerRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *CustomerRequest) GetAddresses() []*CustomerRequest_Address {
if m != nil {
return m.Addresses
}
return nil
}
type CustomerRequest_Address struct {
Street string `protobuf:"bytes,1,opt,name=street" json:"street,omitempty"`
City string `protobuf:"bytes,2,opt,name=city" json:"city,omitempty"`
State string `protobuf:"bytes,3,opt,name=state" json:"state,omitempty"`
Zip string `protobuf:"bytes,4,opt,name=zip" json:"zip,omitempty"`
IsShippingAddress bool `protobuf:"varint,5,opt,name=isShippingAddress" json:"isShippingAddress,omitempty"`
}
func (m *CustomerRequest_Address) Reset() { *m = CustomerRequest_Address{} }
func (m *CustomerRequest_Address) String() string { return proto.CompactTextString(m) }
func (*CustomerRequest_Address) ProtoMessage() {}
func (*CustomerRequest_Address) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} }
type CustomerResponse struct {
Id int32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"`
Success bool `protobuf:"varint,2,opt,name=success" json:"success,omitempty"`
}
func (m *CustomerResponse) Reset() { *m = CustomerResponse{} }
func (m *CustomerResponse) String() string { return proto.CompactTextString(m) }
func (*CustomerResponse) ProtoMessage() {}
func (*CustomerResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
type CustomerFilter struct {
Keyword string `protobuf:"bytes,1,opt,name=keyword" json:"keyword,omitempty"`
}
func (m *CustomerFilter) Reset() { *m = CustomerFilter{} }
func (m *CustomerFilter) String() string { return proto.CompactTextString(m) }
func (*CustomerFilter) ProtoMessage() {}
func (*CustomerFilter) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func init() {
proto.RegisterType((*CustomerRequest)(nil), "customer.CustomerRequest")
proto.RegisterType((*CustomerRequest_Address)(nil), "customer.CustomerRequest.Address")
proto.RegisterType((*CustomerResponse)(nil), "customer.CustomerResponse")
proto.RegisterType((*CustomerFilter)(nil), "customer.CustomerFilter")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion3
// Client API for Customer service
type CustomerClient interface {
// Get all Customers with filter - A server-to-client streaming RPC.
GetCustomers(ctx context.Context, in *CustomerFilter, opts ...grpc.CallOption) (Customer_GetCustomersClient, error)
// Create a new Customer - A simple RPC
CreateCustomer(ctx context.Context, in *CustomerRequest, opts ...grpc.CallOption) (*CustomerResponse, error)
}
type customerClient struct {
cc *grpc.ClientConn
}
func NewCustomerClient(cc *grpc.ClientConn) CustomerClient {
return &customerClient{cc}
}
func (c *customerClient) GetCustomers(ctx context.Context, in *CustomerFilter, opts ...grpc.CallOption) (Customer_GetCustomersClient, error) {
stream, err := grpc.NewClientStream(ctx, &_Customer_serviceDesc.Streams[0], c.cc, "/customer.Customer/GetCustomers", opts...)
if err != nil {
return nil, err
}
x := &customerGetCustomersClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
type Customer_GetCustomersClient interface {
Recv() (*CustomerRequest, error)
grpc.ClientStream
}
type customerGetCustomersClient struct {
grpc.ClientStream
}
func (x *customerGetCustomersClient) Recv() (*CustomerRequest, error) {
m := new(CustomerRequest)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *customerClient) CreateCustomer(ctx context.Context, in *CustomerRequest, opts ...grpc.CallOption) (*CustomerResponse, error) {
out := new(CustomerResponse)
err := grpc.Invoke(ctx, "/customer.Customer/CreateCustomer", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Customer service
type CustomerServer interface {
// Get all Customers with filter - A server-to-client streaming RPC.
GetCustomers(*CustomerFilter, Customer_GetCustomersServer) error
// Create a new Customer - A simple RPC
CreateCustomer(context.Context, *CustomerRequest) (*CustomerResponse, error)
}
func RegisterCustomerServer(s *grpc.Server, srv CustomerServer) {
s.RegisterService(&_Customer_serviceDesc, srv)
}
func _Customer_GetCustomers_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(CustomerFilter)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(CustomerServer).GetCustomers(m, &customerGetCustomersServer{stream})
}
type Customer_GetCustomersServer interface {
Send(*CustomerRequest) error
grpc.ServerStream
}
type customerGetCustomersServer struct {
grpc.ServerStream
}
func (x *customerGetCustomersServer) Send(m *CustomerRequest) error {
return x.ServerStream.SendMsg(m)
}
func _Customer_CreateCustomer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CustomerRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CustomerServer).CreateCustomer(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/customer.Customer/CreateCustomer",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CustomerServer).CreateCustomer(ctx, req.(*CustomerRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Customer_serviceDesc = grpc.ServiceDesc{
ServiceName: "customer.Customer",
HandlerType: (*CustomerServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "CreateCustomer",
Handler: _Customer_CreateCustomer_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "GetCustomers",
Handler: _Customer_GetCustomers_Handler,
ServerStreams: true,
},
},
Metadata: fileDescriptor0,
}
func init() { proto.RegisterFile("customer.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 326 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x92, 0xef, 0x4a, 0xc3, 0x30,
0x10, 0xc0, 0x97, 0x6e, 0xdd, 0x9f, 0x53, 0xea, 0x0c, 0x22, 0xb1, 0x9f, 0x6a, 0x3f, 0x15, 0x91,
0x21, 0xf3, 0xab, 0x20, 0x32, 0x70, 0xf8, 0xb5, 0x3e, 0x41, 0x6d, 0x0f, 0x17, 0xdc, 0xda, 0x9a,
0xcb, 0x90, 0xf9, 0x0a, 0xbe, 0x83, 0xcf, 0xe0, 0x23, 0x4a, 0xd2, 0x66, 0x03, 0xe7, 0xbe, 0xdd,
0xef, 0x72, 0x77, 0xf9, 0xe5, 0x08, 0x04, 0xf9, 0x9a, 0x74, 0xb5, 0x42, 0x35, 0xa9, 0x55, 0xa5,
0x2b, 0x3e, 0x74, 0x1c, 0xff, 0x78, 0x70, 0x32, 0x6b, 0x21, 0xc5, 0xf7, 0x35, 0x92, 0xe6, 0x01,
0x78, 0xb2, 0x10, 0x2c, 0x62, 0x89, 0x9f, 0x7a, 0xb2, 0xe0, 0x1c, 0x7a, 0x65, 0xb6, 0x42, 0xe1,
0x45, 0x2c, 0x19, 0xa5, 0x36, 0xe6, 0x67, 0xe0, 0xe3, 0x2a, 0x93, 0x4b, 0xd1, 0xb5, 0xc9, 0x06,
0x4c, 0xb6, 0x5e, 0x54, 0x25, 0x8a, 0x5e, 0x93, 0xb5, 0xc0, 0xef, 0x61, 0x94, 0x15, 0x85, 0x42,
0x22, 0x24, 0xe1, 0x47, 0xdd, 0xe4, 0x68, 0x7a, 0x39, 0xd9, 0x1a, 0xfd, 0xb9, 0x7d, 0xf2, 0xd0,
0x94, 0xa6, 0xbb, 0x9e, 0xf0, 0x8b, 0xc1, 0xa0, 0x4d, 0xf3, 0x73, 0xe8, 0x93, 0x56, 0x88, 0xda,
0x0a, 0x8e, 0xd2, 0x96, 0x8c, 0x64, 0x2e, 0xf5, 0xc6, 0x49, 0x9a, 0xd8, 0xe8, 0x90, 0xce, 0x34,
0x3a, 0x49, 0x0b, 0x7c, 0x0c, 0xdd, 0x4f, 0x59, 0xb7, 0x8a, 0x26, 0xe4, 0xd7, 0x70, 0x2a, 0xe9,
0x79, 0x21, 0xeb, 0x5a, 0x96, 0xaf, 0xed, 0x45, 0xc2, 0x8f, 0x58, 0x32, 0x4c, 0xf7, 0x0f, 0xe2,
0x3b, 0x18, 0xef, 0x9c, 0xa9, 0xae, 0x4a, 0xc2, 0xbd, 0x95, 0x09, 0x18, 0xd0, 0x3a, 0xcf, 0xcd,
0x1c, 0xcf, 0xce, 0x71, 0x18, 0x5f, 0x41, 0xe0, 0xba, 0x1f, 0xe5, 0x52, 0xa3, 0x32, 0xb5, 0x6f,
0xb8, 0xf9, 0xa8, 0x54, 0xd1, 0x3e, 0xc9, 0xe1, 0xf4, 0x9b, 0xc1, 0xd0, 0x15, 0xf3, 0x39, 0x1c,
0xcf, 0x51, 0x3b, 0x24, 0x2e, 0xf6, 0x57, 0xd8, 0x0c, 0x0c, 0x2f, 0x0e, 0x2e, 0x37, 0xee, 0xdc,
0x30, 0xfe, 0x04, 0xc1, 0x4c, 0x61, 0xa6, 0x71, 0x3b, 0xfa, 0x70, 0x43, 0x18, 0xfe, 0x77, 0xd4,
0x3c, 0x3a, 0xee, 0xbc, 0xf4, 0xed, 0x77, 0xba, 0xfd, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xde, 0x91,
0xd3, 0x62, 0x60, 0x02, 0x00, 0x00,
}
================================================
FILE: grpc/customer/customer.proto
================================================
syntax = "proto3";
package customer;
// The Customer service definition.
service Customer {
// Get all Customers with filter - A server-to-client streaming RPC.
rpc GetCustomers(CustomerFilter) returns (stream CustomerRequest) {}
// Create a new Customer - A simple RPC
rpc CreateCustomer (CustomerRequest) returns (CustomerResponse) {}
}
// Request message for creating a new customer
message CustomerRequest {
int32 id = 1; // Unique ID number for a Customer.
string name = 2;
string email = 3;
string phone= 4;
message Address {
string street = 1;
string city = 2;
string state = 3;
string zip = 4;
bool isShippingAddress = 5;
}
repeated Address addresses = 5;
}
message CustomerResponse {
int32 id = 1;
bool success = 2;
}
message CustomerFilter {
string keyword = 1;
}
================================================
FILE: grpc/server/main.go
================================================
package main
import (
"log"
"net"
"strings"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "github.com/shijuvar/go-recipes/grpc/customer"
)
const (
port = ":50051"
)
// server is used to implement customer.CustomerServer.
type server struct {
savedCustomers []*pb.CustomerRequest
}
// CreateCustomer creates a new Customer
func (s *server) CreateCustomer(ctx context.Context, in *pb.CustomerRequest) (*pb.CustomerResponse, error) {
s.savedCustomers = append(s.savedCustomers, in)
return &pb.CustomerResponse{Id: in.Id, Success: true}, nil
}
// GetCustomers returns all customers by given filter
func (s *server) GetCustomers(filter *pb.CustomerFilter, stream pb.Customer_GetCustomersServer) error {
for _, customer := range s.savedCustomers {
if filter.Keyword != "" {
if !strings.Contains(customer.Name, filter.Keyword) {
continue
}
}
if err := stream.Send(customer); err != nil {
return err
}
}
return nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
// Creates a new gRPC server
s := grpc.NewServer()
pb.RegisterCustomerServer(s, &server{})
s.Serve(lis)
}
gitextract_fqtkzqqz/
├── .gitignore
├── LICENSE
├── README.md
├── binarypkg/
│ ├── src/
│ │ └── github.com/
│ │ └── shijuvar/
│ │ └── binarypkg/
│ │ └── utils.go
│ └── utils.go
├── binarypkgdemo/
│ └── main.go
├── ch01/
│ ├── declarations/
│ │ ├── enum.go
│ │ ├── main.go
│ │ └── main1.go
│ ├── favorites/
│ │ └── main.go
│ ├── hello/
│ │ └── main.go
│ ├── lib/
│ │ ├── favorites.go
│ │ └── utils.go
│ ├── loop/
│ │ └── main.go
│ ├── strutils/
│ │ └── utils.go
│ ├── strutilsdemo/
│ │ └── main.go
│ ├── typeconv/
│ │ └── main.go
│ └── vetting/
│ └── main.go
├── ch02/
│ ├── arrays/
│ │ └── main.go
│ ├── defer/
│ │ ├── deferfunc.go
│ │ └── panicrecover.go
│ ├── functions/
│ │ ├── calc.go
│ │ ├── closures.go
│ │ ├── swap.go
│ │ └── variadic.go
│ ├── maps/
│ │ ├── main.go
│ │ └── sort_map.go
│ └── slices/
│ ├── append.go
│ ├── append_nilslice.go
│ ├── copy.go
│ ├── iterate.go
│ ├── main.go
│ └── slicing.go
├── ch03/
│ ├── ecommerce/
│ │ ├── main.go
│ │ └── models.go
│ ├── employee/
│ │ └── employee.go
│ ├── person.go
│ └── pointer/
│ └── main.go
├── ch04/
│ ├── channels/
│ │ └── main.go
│ ├── deadlock/
│ │ ├── main.go
│ │ └── main_deadlock.go
│ ├── mathtable/
│ │ └── main.go
│ ├── pipeline/
│ │ ├── main.go
│ │ └── main1.go
│ ├── select/
│ │ ├── context.go
│ │ └── main.go
│ ├── unbuffercounter/
│ │ ├── main.go
│ │ └── main1.go
│ └── worker/
│ └── main.go
├── ch05/
│ ├── archivetar/
│ │ └── main.go
│ ├── archivezip/
│ │ └── main.go
│ ├── cmdflags/
│ │ └── main.go
│ ├── flag/
│ │ └── main.go
│ ├── json/
│ │ └── main.go
│ ├── jsontag/
│ │ └── main.go
│ ├── log/
│ │ ├── logger.go
│ │ └── main.go
│ └── simplelog/
│ └── main.go
├── ch06/
│ ├── influx/
│ │ └── main.go
│ ├── mongo/
│ │ ├── bookmark_store.go
│ │ └── main.go
│ ├── postgres/
│ │ └── main.go
│ └── rethink/
│ ├── bookmark_store.go
│ └── main.go
├── ch07/
│ ├── bookmarkapi/
│ │ ├── common/
│ │ │ ├── auth.go
│ │ │ ├── bootstrapper.go
│ │ │ ├── config.json
│ │ │ ├── logger.go
│ │ │ ├── mongo_utils.go
│ │ │ └── utils.go
│ │ ├── controllers/
│ │ │ ├── bookmark_controller.go
│ │ │ ├── resources.go
│ │ │ └── user_controller.go
│ │ ├── keys/
│ │ │ ├── app.rsa
│ │ │ └── app.rsa.pub
│ │ ├── main.go
│ │ ├── model/
│ │ │ └── models.go
│ │ ├── routers/
│ │ │ ├── bookmark.go
│ │ │ ├── routers.go
│ │ │ └── user.go
│ │ └── store/
│ │ ├── bookmark_store.go
│ │ └── user_store.go
│ ├── customhandler/
│ │ └── main.go
│ ├── defaultservemux/
│ │ └── main.go
│ ├── handlefunc/
│ │ └── main.go
│ ├── handlerfunc/
│ │ └── main.go
│ ├── httpserver/
│ │ └── main.go
│ ├── middleware/
│ │ └── main.go
│ └── server/
│ └── main.go
├── ch08/
│ ├── calc/
│ │ ├── calc.go
│ │ └── calc_test.go
│ ├── httpbdd/
│ │ ├── controllers/
│ │ │ ├── controllers_suite_test.go
│ │ │ ├── user_controller.go
│ │ │ └── user_controller_test.go
│ │ ├── main.go
│ │ ├── model/
│ │ │ └── user.go
│ │ └── store/
│ │ └── user_store.go
│ └── httptest/
│ ├── main.go
│ └── main_test.go
└── grpc/
├── client/
│ └── main.go
├── customer/
│ ├── customer.pb.go
│ └── customer.proto
└── server/
└── main.go
SYMBOL INDEX (362 symbols across 95 files)
FILE: binarypkg/utils.go
function ToUpperCase (line 6) | func ToUpperCase(s string) string {
function ToLowerCase (line 11) | func ToLowerCase(s string) string {
FILE: binarypkgdemo/main.go
function main (line 9) | func main() {
FILE: ch01/declarations/enum.go
constant UNSPECIFIED (line 7) | UNSPECIFIED Level = iota
constant TRACE (line 9) | TRACE
constant INFO (line 11) | INFO
constant WARNING (line 13) | WARNING
constant ERROR (line 15) | ERROR
type Level (line 19) | type Level
method String (line 31) | func (l Level) String() string {
function main (line 35) | func main() {
FILE: ch01/declarations/main.go
constant Title (line 6) | Title = "Person Details"
function main (line 11) | func main() {
FILE: ch01/declarations/main1.go
constant Title (line 6) | Title string = "Person Details"
function main (line 11) | func main() {
FILE: ch01/favorites/main.go
function main (line 9) | func main() {
FILE: ch01/hello/main.go
function main (line 5) | func main() {
FILE: ch01/lib/favorites.go
function init (line 7) | func init() {
function Add (line 15) | func Add(favorite string) {
function GetAll (line 20) | func GetAll() []string {
FILE: ch01/lib/utils.go
function PrintFavorites (line 8) | func PrintFavorites() {
FILE: ch01/loop/main.go
function main (line 5) | func main() {
function sum (line 9) | func sum() {
function sum1 (line 16) | func sum1() {
FILE: ch01/strutils/utils.go
function ToUpperCase (line 10) | func ToUpperCase(s string) string {
function ToLowerCase (line 15) | func ToLowerCase(s string) string {
function ToFirstUpper (line 20) | func ToFirstUpper(s string) string {
FILE: ch01/strutilsdemo/main.go
function main (line 9) | func main() {
FILE: ch01/typeconv/main.go
function main (line 8) | func main() {
FILE: ch01/vetting/main.go
function main (line 5) | func main() {
FILE: ch02/arrays/main.go
function main (line 7) | func main() {
FILE: ch02/defer/deferfunc.go
function ReadFile (line 9) | func ReadFile(filename string) ([]byte, error) {
function main (line 18) | func main() {
FILE: ch02/defer/panicrecover.go
function panicRecover (line 7) | func panicRecover() {
function main (line 21) | func main() {
FILE: ch02/functions/calc.go
function Add (line 7) | func Add(x, y int) int {
function Subtract (line 11) | func Subtract(x, y int) int {
function main (line 15) | func main() {
FILE: ch02/functions/closures.go
function SplitValues (line 7) | func SplitValues(f func(sum int) (int, int)) {
function main (line 15) | func main() {
FILE: ch02/functions/swap.go
function Swap (line 7) | func Swap(x, y string) (string, string) {
function main (line 11) | func main() {
FILE: ch02/functions/variadic.go
function Sum (line 7) | func Sum(nums ...int) int {
function main (line 15) | func main() {
FILE: ch02/maps/main.go
function main (line 7) | func main() {
function removeLan (line 48) | func removeLan(langs map[string]string, key string) {
FILE: ch02/maps/sort_map.go
function main (line 8) | func main() {
FILE: ch02/slices/append.go
function main (line 7) | func main() {
FILE: ch02/slices/append_nilslice.go
function main (line 5) | func main() {
FILE: ch02/slices/copy.go
function main (line 7) | func main() {
FILE: ch02/slices/iterate.go
function main (line 7) | func main() {
FILE: ch02/slices/main.go
function main (line 7) | func main() {
FILE: ch02/slices/slicing.go
function main (line 7) | func main() {
FILE: ch03/ecommerce/main.go
function main (line 8) | func main() {
FILE: ch03/ecommerce/models.go
type Address (line 8) | type Address struct
type Customer (line 13) | type Customer struct
method ToString (line 18) | func (c Customer) ToString() string {
method ShippingAddress (line 21) | func (c Customer) ShippingAddress() string {
type Order (line 30) | type Order struct
method GrandTotal (line 38) | func (o *Order) GrandTotal() float64 {
method ToString (line 45) | func (o *Order) ToString() string {
method ChangeStatus (line 58) | func (o *Order) ChangeStatus(newStatus string) {
type OrderItem (line 62) | type OrderItem struct
method Total (line 67) | func (item OrderItem) Total() float64 {
method ToString (line 70) | func (item OrderItem) ToString() string {
type Product (line 77) | type Product struct
FILE: ch03/employee/employee.go
type TeamMember (line 9) | type TeamMember interface
type Employee (line 14) | type Employee struct
method PrintName (line 20) | func (e Employee) PrintName() {
method PrintDetails (line 24) | func (e Employee) PrintDetails() {
type Developer (line 28) | type Developer struct
method PrintDetails (line 34) | func (d Developer) PrintDetails() {
type Manager (line 43) | type Manager struct
method PrintDetails (line 50) | func (m Manager) PrintDetails() {
type Team (line 63) | type Team struct
method PrintTeamDetails (line 68) | func (t Team) PrintTeamDetails() {
function main (line 77) | func main() {
FILE: ch03/person.go
type Person (line 11) | type Person struct
method PrintName (line 18) | func (p Person) PrintName() {
method PrintDetails (line 23) | func (p Person) PrintDetails() {
function main (line 27) | func main() {
FILE: ch03/pointer/main.go
type Person (line 10) | type Person struct
method PrintName (line 17) | func (p *Person) PrintName() {
method PrintDetails (line 22) | func (p *Person) PrintDetails() {
method ChangeLocation (line 27) | func (p *Person) ChangeLocation(newLocation string) {
function main (line 30) | func main() {
FILE: ch04/channels/main.go
function main (line 7) | func main() {
FILE: ch04/deadlock/main.go
function main (line 7) | func main() {
FILE: ch04/deadlock/main_deadlock.go
function main (line 7) | func main() {
FILE: ch04/mathtable/main.go
function main (line 14) | func main() {
function addTable (line 29) | func addTable() {
function multiTable (line 43) | func multiTable() {
FILE: ch04/pipeline/main.go
type fibvalue (line 10) | type fibvalue struct
function randomCounter (line 16) | func randomCounter(out chan<- int) {
function generateFibonacci (line 26) | func generateFibonacci(out chan<- fibvalue, in <-chan int) {
function printFibonacci (line 43) | func printFibonacci(in <-chan fibvalue) {
function main (line 50) | func main() {
FILE: ch04/pipeline/main1.go
type fibvalue (line 10) | type fibvalue struct
function randomCounter (line 17) | func randomCounter(out chan int) {
function generateFibonacci (line 28) | func generateFibonacci(out chan fibvalue, in chan int) {
function printFibonacci (line 46) | func printFibonacci(in chan fibvalue) {
function main (line 53) | func main() {
FILE: ch04/select/context.go
function generateValues (line 8) | func generateValues(ctx context.Context, counter chan int) {
function main (line 20) | func main() {
FILE: ch04/select/main.go
type fibvalue (line 11) | type fibvalue struct
type squarevalue (line 14) | type squarevalue struct
function generateSquare (line 19) | func generateSquare(sqrs chan<- squarevalue) {
function generateFibonacci (line 29) | func generateFibonacci(fibs chan<- fibvalue) {
function printValues (line 43) | func printValues(fibs <-chan fibvalue, sqrs <-chan squarevalue) {
function main (line 58) | func main() {
FILE: ch04/unbuffercounter/main.go
function main (line 12) | func main() {
function printCounts (line 31) | func printCounts(label string, count chan int) {
FILE: ch04/unbuffercounter/main1.go
function main (line 12) | func main() {
function printCounts (line 31) | func printCounts(label string, count chan int) {
FILE: ch04/worker/main.go
type Task (line 13) | type Task struct
method Run (line 20) | func (t *Task) Run() {
constant noOfWorkers (line 31) | noOfWorkers = 3
function main (line 34) | func main() {
function worker (line 63) | func worker(taskQueue <-chan *Task, workerId int) {
FILE: ch05/archivetar/main.go
function addToArchive (line 13) | func addToArchive(filename string, tw *tar.Writer) error {
function archiveFiles (line 46) | func archiveFiles(files []string, archive string) error {
function readArchive (line 70) | func readArchive(archive string) error {
function main (line 106) | func main() {
FILE: ch05/archivezip/main.go
function addToArchive (line 12) | func addToArchive(filename string, zw *zip.Writer) error {
function archiveFiles (line 33) | func archiveFiles(files []string, archive string) error {
function readArchive (line 55) | func readArchive(archive string) error {
function main (line 84) | func main() {
FILE: ch05/cmdflags/main.go
function main (line 8) | func main() {
FILE: ch05/flag/main.go
function main (line 8) | func main() {
FILE: ch05/json/main.go
type Employee (line 9) | type Employee struct
function main (line 14) | func main() {
FILE: ch05/jsontag/main.go
type Employee (line 9) | type Employee struct
function main (line 16) | func main() {
FILE: ch05/log/logger.go
constant UNSPECIFIED (line 12) | UNSPECIFIED Level = iota
constant TRACE (line 14) | TRACE
constant INFO (line 16) | INFO
constant WARNING (line 18) | WARNING
constant ERROR (line 20) | ERROR
type Level (line 24) | type Level
function initLog (line 35) | func initLog(
function SetLogLevel (line 57) | func SetLogLevel(level Level) {
FILE: ch05/log/main.go
function main (line 8) | func main() {
function loop (line 22) | func loop() {
FILE: ch05/simplelog/main.go
function initLog (line 20) | func initLog(
function main (line 37) | func main() {
function loop (line 45) | func loop() {
FILE: ch06/influx/main.go
constant DB (line 16) | DB = "metricsdb"
constant username (line 17) | username = "opsadmin"
constant password (line 18) | password = "pass123"
function main (line 21) | func main() {
function influxDBClient (line 38) | func influxDBClient() client.Client {
function createMetrics (line 51) | func createMetrics(clnt client.Client) {
function queryDB (line 92) | func queryDB(clnt client.Client, command string) (res []client.Result, e...
function readWithLimit (line 111) | func readWithLimit(clnt client.Client, limit int) {
function meanCPUUsage (line 129) | func meanCPUUsage(clnt client.Client, region string) {
function countRegion (line 144) | func countRegion(clnt client.Client, region string) {
FILE: ch06/mongo/bookmark_store.go
type Bookmark (line 11) | type Bookmark struct
type BookmarkStore (line 20) | type BookmarkStore struct
method Create (line 25) | func (store BookmarkStore) Create(b *Bookmark) error {
method Update (line 33) | func (store BookmarkStore) Update(b Bookmark) error {
method Delete (line 47) | func (store BookmarkStore) Delete(id string) error {
method GetAll (line 53) | func (store BookmarkStore) GetAll() []Bookmark {
method GetByID (line 64) | func (store BookmarkStore) GetByID(id string) (Bookmark, error) {
method GetByTag (line 71) | func (store BookmarkStore) GetByTag(tags []string) []Bookmark {
FILE: ch06/mongo/main.go
function init (line 15) | func init() {
function createUpdate (line 31) | func createUpdate() {
function getByID (line 73) | func getByID(id string) {
function getAll (line 83) | func getAll() {
function getByTags (line 96) | func getByTags() {
function delete (line 113) | func delete() {
function main (line 122) | func main() {
FILE: ch06/postgres/main.go
type Product (line 12) | type Product struct
function init (line 21) | func init() {
function main (line 28) | func main() {
function createProduct (line 43) | func createProduct(prd Product) {
function getProducts (line 55) | func getProducts() {
function getProductByID (line 84) | func getProductByID(id int) {
FILE: ch06/rethink/bookmark_store.go
type Bookmark (line 10) | type Bookmark struct
type BookmarkStore (line 19) | type BookmarkStore struct
method Create (line 24) | func (store BookmarkStore) Create(b *Bookmark) error {
method Update (line 35) | func (store BookmarkStore) Update(b Bookmark) error {
method Delete (line 49) | func (store BookmarkStore) Delete(id string) error {
method GetAll (line 55) | func (store BookmarkStore) GetAll() ([]Bookmark, error) {
method GetByID (line 64) | func (store BookmarkStore) GetByID(id string) (Bookmark, error) {
FILE: ch06/rethink/main.go
function initDB (line 15) | func initDB(session *r.Session) {
function changeFeeds (line 30) | func changeFeeds(session *r.Session) {
function init (line 50) | func init() {
function createUpdate (line 72) | func createUpdate() {
function getByID (line 113) | func getByID(id string) {
function getAll (line 122) | func getAll() {
function delete (line 138) | func delete() {
function main (line 150) | func main() {
FILE: ch07/bookmarkapi/common/auth.go
type AppClaims (line 18) | type AppClaims struct
constant privKeyPath (line 28) | privKeyPath = "keys/app.rsa"
constant pubKeyPath (line 30) | pubKeyPath = "keys/app.rsa.pub"
function initKeys (line 41) | func initKeys() {
function GenerateJWT (line 65) | func GenerateJWT(name, role string) (string, error) {
function AuthorizeRequest (line 84) | func AuthorizeRequest(next http.Handler) http.Handler {
function AuthorizeRequestWithNegroni (line 144) | func AuthorizeRequestWithNegroni(w http.ResponseWriter, r *http.Request,...
function TokenFromAuthHeader (line 202) | func TokenFromAuthHeader(r *http.Request) (string, error) {
FILE: ch07/bookmarkapi/common/bootstrapper.go
function StartUp (line 4) | func StartUp() {
FILE: ch07/bookmarkapi/common/logger.go
constant UNSPECIFIED (line 12) | UNSPECIFIED Level = iota
constant TRACE (line 14) | TRACE
constant INFO (line 16) | INFO
constant WARNING (line 18) | WARNING
constant ERROR (line 20) | ERROR
type Level (line 24) | type Level
function initLog (line 35) | func initLog(
function setLogLevel (line 57) | func setLogLevel(level Level) {
FILE: ch07/bookmarkapi/common/mongo_utils.go
function getSession (line 13) | func getSession() *mgo.Session {
function createDBSession (line 28) | func createDBSession() {
function addIndexes (line 42) | func addIndexes() {
type DataStore (line 62) | type DataStore struct
method Close (line 68) | func (ds *DataStore) Close() {
method Collection (line 73) | func (ds *DataStore) Collection(name string) *mgo.Collection {
function NewDataStore (line 78) | func NewDataStore() *DataStore {
FILE: ch07/bookmarkapi/common/utils.go
type appError (line 11) | type appError struct
type errorResource (line 16) | type errorResource struct
type configuration (line 19) | type configuration struct
function DisplayAppError (line 26) | func DisplayAppError(w http.ResponseWriter, handlerError error, message ...
function initConfig (line 45) | func initConfig() {
function loadAppConfig (line 50) | func loadAppConfig() {
FILE: ch07/bookmarkapi/controllers/bookmark_controller.go
function CreateBookmark (line 17) | func CreateBookmark(w http.ResponseWriter, r *http.Request) {
function GetBookmarks (line 76) | func GetBookmarks(w http.ResponseWriter, r *http.Request) {
function GetBookmarkByID (line 99) | func GetBookmarkByID(w http.ResponseWriter, r *http.Request) {
function GetBookmarksByUser (line 142) | func GetBookmarksByUser(w http.ResponseWriter, r *http.Request) {
function UpdateBookmark (line 168) | func UpdateBookmark(w http.ResponseWriter, r *http.Request) {
function DeleteBookmark (line 206) | func DeleteBookmark(w http.ResponseWriter, r *http.Request) {
FILE: ch07/bookmarkapi/controllers/resources.go
type UserResource (line 10) | type UserResource struct
type AuthUserResource (line 14) | type AuthUserResource struct
type BookmarkResource (line 19) | type BookmarkResource struct
type BookmarksResource (line 23) | type BookmarksResource struct
type UserModel (line 28) | type UserModel struct
type AuthUserModel (line 35) | type AuthUserModel struct
FILE: ch07/bookmarkapi/controllers/user_controller.go
function Register (line 14) | func Register(w http.ResponseWriter, r *http.Request) {
function Login (line 45) | func Login(w http.ResponseWriter, r *http.Request) {
FILE: ch07/bookmarkapi/main.go
function main (line 12) | func main() {
FILE: ch07/bookmarkapi/model/models.go
type User (line 11) | type User struct
type Bookmark (line 19) | type Bookmark struct
FILE: ch07/bookmarkapi/routers/bookmark.go
function SetBookmarkRoutes (line 11) | func SetBookmarkRoutes(router *mux.Router) *mux.Router {
FILE: ch07/bookmarkapi/routers/routers.go
function InitRoutes (line 8) | func InitRoutes() *mux.Router {
FILE: ch07/bookmarkapi/routers/user.go
function SetUserRoutes (line 10) | func SetUserRoutes(router *mux.Router) *mux.Router {
FILE: ch07/bookmarkapi/store/bookmark_store.go
type BookmarkStore (line 13) | type BookmarkStore struct
method Create (line 18) | func (store BookmarkStore) Create(b *model.Bookmark) error {
method Update (line 27) | func (store BookmarkStore) Update(b model.Bookmark) error {
method Delete (line 41) | func (store BookmarkStore) Delete(id string) error {
method GetAll (line 47) | func (store BookmarkStore) GetAll() []model.Bookmark {
method GetByUser (line 58) | func (store BookmarkStore) GetByUser(user string) []model.Bookmark {
method GetByID (line 69) | func (store BookmarkStore) GetByID(id string) (model.Bookmark, error) {
method GetByTag (line 76) | func (store BookmarkStore) GetByTag(tags []string) []model.Bookmark {
FILE: ch07/bookmarkapi/store/user_store.go
type UserStore (line 12) | type UserStore struct
method Create (line 17) | func (store UserStore) Create(user model.User, password string) error {
method Login (line 30) | func (store UserStore) Login(email, password string) (model.User, erro...
FILE: ch07/customhandler/main.go
type textHandler (line 9) | type textHandler struct
method ServeHTTP (line 13) | func (th *textHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques...
type indexHandler (line 17) | type indexHandler struct
method ServeHTTP (line 20) | func (ih *indexHandler) ServeHTTP(w http.ResponseWriter, r *http.Reque...
function main (line 42) | func main() {
FILE: ch07/defaultservemux/main.go
function index (line 9) | func index(w http.ResponseWriter, r *http.Request) {
function welcome (line 30) | func welcome(w http.ResponseWriter, r *http.Request) {
function message (line 33) | func message(w http.ResponseWriter, r *http.Request) {
function main (line 37) | func main() {
FILE: ch07/handlefunc/main.go
function index (line 9) | func index(w http.ResponseWriter, r *http.Request) {
function welcome (line 30) | func welcome(w http.ResponseWriter, r *http.Request) {
function message (line 33) | func message(w http.ResponseWriter, r *http.Request) {
function main (line 37) | func main() {
FILE: ch07/handlerfunc/main.go
function textResponseHandler (line 9) | func textResponseHandler(resposeText string) http.Handler {
function index (line 14) | func index(w http.ResponseWriter, r *http.Request) {
function welcome (line 35) | func welcome(w http.ResponseWriter, r *http.Request) {
function message (line 38) | func message(w http.ResponseWriter, r *http.Request) {
function main (line 42) | func main() {
FILE: ch07/httpserver/main.go
function handler (line 8) | func handler(w http.ResponseWriter, r *http.Request) {
function main (line 12) | func main() {
FILE: ch07/middleware/main.go
function loggingHandler (line 11) | func loggingHandler(next http.Handler) http.Handler {
function index (line 22) | func index(w http.ResponseWriter, r *http.Request) {
function welcome (line 43) | func welcome(w http.ResponseWriter, r *http.Request) {
function message (line 46) | func message(w http.ResponseWriter, r *http.Request) {
function favicon (line 49) | func favicon(w http.ResponseWriter, r *http.Request) {
function main (line 52) | func main() {
FILE: ch07/server/main.go
function index (line 10) | func index(w http.ResponseWriter, r *http.Request) {
function main (line 14) | func main() {
FILE: ch08/calc/calc.go
function Sum (line 7) | func Sum(nums ...int) int {
function Average (line 17) | func Average(nums ...int) float64 {
FILE: ch08/calc/calc_test.go
function TestSum (line 10) | func TestSum(t *testing.T) {
function TestAverage (line 21) | func TestAverage(t *testing.T) {
function BenchmarkSum (line 31) | func BenchmarkSum(b *testing.B) {
function BenchmarkAverage (line 38) | func BenchmarkAverage(b *testing.B) {
function TestLongRun (line 44) | func TestLongRun(t *testing.T) {
function TestSumInParallel (line 54) | func TestSumInParallel(t *testing.T) {
function TestAverageInParallel (line 68) | func TestAverageInParallel(t *testing.T) {
function ExampleSum (line 81) | func ExampleSum() {
function ExampleAverage (line 87) | func ExampleAverage() {
FILE: ch08/httpbdd/controllers/controllers_suite_test.go
function TestControllers (line 10) | func TestControllers(t *testing.T) {
FILE: ch08/httpbdd/controllers/user_controller.go
function GetUsers (line 12) | func GetUsers(store model.UserStore) http.Handler {
function CreateUser (line 28) | func CreateUser(store model.UserStore) http.Handler {
FILE: ch08/httpbdd/controllers/user_controller_test.go
type FakeUserStore (line 82) | type FakeUserStore struct
method GetUsers (line 87) | func (store *FakeUserStore) GetUsers() []model.User {
method AddUser (line 92) | func (store *FakeUserStore) AddUser(user model.User) error {
function newFakeUserStore (line 104) | func newFakeUserStore() *FakeUserStore {
FILE: ch08/httpbdd/main.go
function setUserRoutes (line 12) | func setUserRoutes() *mux.Router {
function main (line 20) | func main() {
FILE: ch08/httpbdd/model/user.go
type User (line 9) | type User struct
type UserStore (line 16) | type UserStore interface
FILE: ch08/httpbdd/store/user_store.go
function createDBSession (line 17) | func createDBSession() {
function init (line 29) | func init() {
type MongoUserStore (line 34) | type MongoUserStore struct
method AddUser (line 37) | func (store *MongoUserStore) AddUser(user model.User) error {
method GetUsers (line 56) | func (store *MongoUserStore) GetUsers() []model.User {
FILE: ch08/httptest/main.go
type User (line 11) | type User struct
function getUsers (line 18) | func getUsers(w http.ResponseWriter, r *http.Request) {
function main (line 42) | func main() {
FILE: ch08/httptest/main_test.go
function TestGetUsers (line 13) | func TestGetUsers(t *testing.T) {
function TestGetUsersWithServer (line 29) | func TestGetUsersWithServer(t *testing.T) {
FILE: grpc/client/main.go
constant address (line 14) | address = "localhost:50051"
function createCustomer (line 18) | func createCustomer(client pb.CustomerClient, customer *pb.CustomerReque...
function getCustomers (line 29) | func getCustomers(client pb.CustomerClient, filter *pb.CustomerFilter) {
function main (line 47) | func main() {
FILE: grpc/customer/customer.pb.go
constant _ (line 36) | _ = proto.ProtoPackageIsVersion2
type CustomerRequest (line 39) | type CustomerRequest struct
method Reset (line 47) | func (m *CustomerRequest) Reset() { *m = CustomerRe...
method String (line 48) | func (m *CustomerRequest) String() string { return proto.Co...
method ProtoMessage (line 49) | func (*CustomerRequest) ProtoMessage() {}
method Descriptor (line 50) | func (*CustomerRequest) Descriptor() ([]byte, []int) { return fileDesc...
method GetAddresses (line 52) | func (m *CustomerRequest) GetAddresses() []*CustomerRequest_Address {
type CustomerRequest_Address (line 59) | type CustomerRequest_Address struct
method Reset (line 67) | func (m *CustomerRequest_Address) Reset() { *m = Cu...
method String (line 68) | func (m *CustomerRequest_Address) String() string { return ...
method ProtoMessage (line 69) | func (*CustomerRequest_Address) ProtoMessage() {}
method Descriptor (line 70) | func (*CustomerRequest_Address) Descriptor() ([]byte, []int) { return ...
type CustomerResponse (line 72) | type CustomerResponse struct
method Reset (line 77) | func (m *CustomerResponse) Reset() { *m = CustomerR...
method String (line 78) | func (m *CustomerResponse) String() string { return proto.C...
method ProtoMessage (line 79) | func (*CustomerResponse) ProtoMessage() {}
method Descriptor (line 80) | func (*CustomerResponse) Descriptor() ([]byte, []int) { return fileDes...
type CustomerFilter (line 82) | type CustomerFilter struct
method Reset (line 86) | func (m *CustomerFilter) Reset() { *m = CustomerFil...
method String (line 87) | func (m *CustomerFilter) String() string { return proto.Com...
method ProtoMessage (line 88) | func (*CustomerFilter) ProtoMessage() {}
method Descriptor (line 89) | func (*CustomerFilter) Descriptor() ([]byte, []int) { return fileDescr...
function init (line 91) | func init() {
constant _ (line 104) | _ = grpc.SupportPackageIsVersion3
type CustomerClient (line 108) | type CustomerClient interface
type customerClient (line 115) | type customerClient struct
method GetCustomers (line 123) | func (c *customerClient) GetCustomers(ctx context.Context, in *Custome...
method CreateCustomer (line 155) | func (c *customerClient) CreateCustomer(ctx context.Context, in *Custo...
function NewCustomerClient (line 119) | func NewCustomerClient(cc *grpc.ClientConn) CustomerClient {
type Customer_GetCustomersClient (line 138) | type Customer_GetCustomersClient interface
type customerGetCustomersClient (line 143) | type customerGetCustomersClient struct
method Recv (line 147) | func (x *customerGetCustomersClient) Recv() (*CustomerRequest, error) {
type CustomerServer (line 166) | type CustomerServer interface
function RegisterCustomerServer (line 173) | func RegisterCustomerServer(s *grpc.Server, srv CustomerServer) {
function _Customer_GetCustomers_Handler (line 177) | func _Customer_GetCustomers_Handler(srv interface{}, stream grpc.ServerS...
type Customer_GetCustomersServer (line 185) | type Customer_GetCustomersServer interface
type customerGetCustomersServer (line 190) | type customerGetCustomersServer struct
method Send (line 194) | func (x *customerGetCustomersServer) Send(m *CustomerRequest) error {
function _Customer_CreateCustomer_Handler (line 198) | func _Customer_CreateCustomer_Handler(srv interface{}, ctx context.Conte...
function init (line 235) | func init() { proto.RegisterFile("customer.proto", fileDescriptor0) }
FILE: grpc/server/main.go
constant port (line 15) | port = ":50051"
type server (line 19) | type server struct
method CreateCustomer (line 24) | func (s *server) CreateCustomer(ctx context.Context, in *pb.CustomerRe...
method GetCustomers (line 30) | func (s *server) GetCustomers(filter *pb.CustomerFilter, stream pb.Cus...
function main (line 44) | func main() {
Condensed preview — 103 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (140K chars).
[
{
"path": ".gitignore",
"chars": 294,
"preview": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture spe"
},
{
"path": "LICENSE",
"chars": 1081,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2016 Shiju Varghese\n\nPermission is hereby granted, free of charge, to any person ob"
},
{
"path": "README.md",
"chars": 489,
"preview": "# Go Recipes\nCode examples for the book \"Go Recipes\" by Apress.\n\n# gokit\nCheck out [github.com/shijuvar/gokit](https://g"
},
{
"path": "binarypkg/src/github.com/shijuvar/binarypkg/utils.go",
"chars": 44,
"preview": "//go:binary-only-package\n\npackage binarypkg\n"
},
{
"path": "binarypkg/utils.go",
"chars": 286,
"preview": "package binarypkg\n\nimport \"strings\"\n\n// ToUpperCase returns the string changed with upper case.\nfunc ToUpperCase(s strin"
},
{
"path": "binarypkgdemo/main.go",
"chars": 283,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/shijuvar/go-recipes/binarypkg\"\n)\n\nfunc main() {\n\tstr := \"Golang\"\n\t// Convert"
},
{
"path": "ch01/declarations/enum.go",
"chars": 675,
"preview": "package main\n\nimport \"fmt\"\n\nconst (\n\t// UNSPECIFIED logs nothing\n\tUNSPECIFIED Level = iota // 0 :\n\t// TRACE logs everyth"
},
{
"path": "ch01/declarations/main.go",
"chars": 423,
"preview": "package main\n\nimport \"fmt\"\n\n// Declare constant\nconst Title = \"Person Details\"\n\n// Declare package variable\nvar Country "
},
{
"path": "ch01/declarations/main1.go",
"chars": 454,
"preview": "package main\n\nimport \"fmt\"\n\n// Declare constant\nconst Title string = \"Person Details\"\n\n// Declare package variable\nvar C"
},
{
"path": "ch01/favorites/main.go",
"chars": 483,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\n\tfav \"github.com/shijuvar/go-recipes/ch01/lib\"\n)\n\nfunc main() {\n\t// Print default favorit"
},
{
"path": "ch01/hello/main.go",
"chars": 73,
"preview": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello, World\")\n}\n"
},
{
"path": "ch01/lib/favorites.go",
"chars": 458,
"preview": "package lib\n\n// Stores favorites\nvar favorites []string\n\n// Initialization logic for the package\nfunc init() {\n\tfavorite"
},
{
"path": "ch01/lib/utils.go",
"chars": 132,
"preview": "package lib\n\nimport (\n\t\"fmt\"\n)\n\n// Print all favorites\nfunc PrintFavorites() {\n\tfor _, v := range favorites {\n\t\tfmt.Prin"
},
{
"path": "ch01/loop/main.go",
"chars": 219,
"preview": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tsum()\n\tsum1()\n}\nfunc sum() {\n\tsum := 0\n\tfor i := 0; i < 10; i++ {\n\t\tsum += i\n"
},
{
"path": "ch01/strutils/utils.go",
"chars": 711,
"preview": "// Package strutils provides string utility functions\npackage strutils\n\nimport (\n\t\"strings\"\n\t\"unicode\"\n)\n\n// Returns the"
},
{
"path": "ch01/strutilsdemo/main.go",
"chars": 404,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/shijuvar/go-recipes/ch01/strutils\"\n)\n\nfunc main() {\n\tstr1, str2 := \"Golang\","
},
{
"path": "ch01/typeconv/main.go",
"chars": 442,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n)\n\nfunc main() {\n\t// type conversion: dealing with a type\n\t// The expression T("
},
{
"path": "ch01/vetting/main.go",
"chars": 105,
"preview": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfloatValue:=4.99\n\tfmt.Printf(\"The value is: %d\",floatValue)\n}\n"
},
{
"path": "ch02/arrays/main.go",
"chars": 1197,
"preview": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\t// Declare arrays\n\tvar x [5]int\n\t// Assign values at specific index\n\tx[0"
},
{
"path": "ch02/defer/deferfunc.go",
"chars": 301,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n)\n\nfunc ReadFile(filename string) ([]byte, error) {\n\tf, err := os.Open("
},
{
"path": "ch02/defer/panicrecover.go",
"chars": 488,
"preview": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc panicRecover() {\n\n\tdefer fmt.Println(\"Deferred call - 1\")\n\tdefer func() {\n\t\tfmt.Pr"
},
{
"path": "ch02/functions/calc.go",
"chars": 269,
"preview": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc Add(x, y int) int {\n\treturn x + y\n}\n\nfunc Subtract(x, y int) int {\n\treturn x - y\n}"
},
{
"path": "ch02/functions/closures.go",
"chars": 435,
"preview": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc SplitValues(f func(sum int) (int, int)) {\n\tx, y := f(35)\n\tfmt.Println(x, y)\n\n\tx, y"
},
{
"path": "ch02/functions/swap.go",
"chars": 225,
"preview": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc Swap(x, y string) (string, string) {\n\treturn y, x\n}\n\nfunc main() {\n\tx, y := \"Shiju"
},
{
"path": "ch02/functions/variadic.go",
"chars": 455,
"preview": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc Sum(nums ...int) int {\n\ttotal := 0\n\tfor _, num := range nums {\n\t\ttotal += num\n\t}\n\t"
},
{
"path": "ch02/maps/main.go",
"chars": 996,
"preview": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\t// Declares a nil map\n\tvar chapts map[int]string\n\n\t// Initialize map wit"
},
{
"path": "ch02/maps/sort_map.go",
"chars": 637,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n)\n\nfunc main() {\n\t// Initialize map with make function\n\tchapts := make(map[int]str"
},
{
"path": "ch02/slices/append.go",
"chars": 506,
"preview": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tx := make([]int, 2, 5)\n\tx[0] = 10\n\tx[1] = 20\n\tfmt.Println(\"Slice x:\", x)"
},
{
"path": "ch02/slices/append_nilslice.go",
"chars": 189,
"preview": "package main\n\nimport \"fmt\"\n\nfunc main() {\n\t// Declare a nil slice\n\tvar x []int\n\tfmt.Println(x, len(x), cap(x))\n\tx = appe"
},
{
"path": "ch02/slices/copy.go",
"chars": 392,
"preview": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tx := []int{10, 20, 30}\n\tfmt.Printf(\"[Slice:x] Length is %d Capacity is %"
},
{
"path": "ch02/slices/iterate.go",
"chars": 141,
"preview": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tx := []int{10, 20, 30, 40, 50}\n\tfor k, v := range x {\n\t\tfmt.Printf(\"x[%d"
},
{
"path": "ch02/slices/main.go",
"chars": 489,
"preview": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tx := make([]int, 3, 5)\n\tx[0] = 10\n\tx[1] = 20\n\tx[2] = 30\n\tfmt.Println(x)\n"
},
{
"path": "ch02/slices/slicing.go",
"chars": 375,
"preview": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tx := []int{10, 20, 30, 40, 50}\n\ty := x[1:3]\n\tfmt.Println(\"y:\", y)\n\tfmt.P"
},
{
"path": "ch03/ecommerce/main.go",
"chars": 1267,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc main() {\n\torder := &Order{\n\t\tId: 1001,\n\t\tCustomer: Customer{\n\t\t\tFirstName:"
},
{
"path": "ch03/ecommerce/models.go",
"chars": 1864,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\ntype Address struct {\n\tStreet, City, State, Zip string\n\tIsShippingAddress "
},
{
"path": "ch03/employee/employee.go",
"chars": 2561,
"preview": "// Example program with Interface, Composition and Method Overriding\npackage main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\ntype TeamM"
},
{
"path": "ch03/person.go",
"chars": 1275,
"preview": "// Person struct with methods of pointer receiver\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\n// Person struct\ntype Person"
},
{
"path": "ch03/pointer/main.go",
"chars": 844,
"preview": "// Person struct with methods of pointer receiver\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\ntype Person struct {\n\tFirstN"
},
{
"path": "ch04/channels/main.go",
"chars": 734,
"preview": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\t// Declare a unbuffered channel\n\tcounter := make(chan int)\n\t// Creates a"
},
{
"path": "ch04/deadlock/main.go",
"chars": 259,
"preview": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\t// Declare a unbuffered channel\n\tcounter := make(chan int)\n\t// Perform s"
},
{
"path": "ch04/deadlock/main_deadlock.go",
"chars": 278,
"preview": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\t// Declare a unbuffered channel\n\tcounter := make(chan int)\n\t// This will"
},
{
"path": "ch04/mathtable/main.go",
"chars": 1269,
"preview": "// This sample program demonstrates how to create goroutines\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"sync\"\n\t\"time\"\n"
},
{
"path": "ch04/pipeline/main.go",
"chars": 1128,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"math/rand\"\n\t\"sync\"\n)\n\ntype fibvalue struct {\n\tinput, value int\n}\n\nvar wg sync.Wa"
},
{
"path": "ch04/pipeline/main1.go",
"chars": 1373,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"math/rand\"\n\t\"sync\"\n)\n\ntype fibvalue struct {\n\tinput, value int\n}\n\nvar wg sync.Wa"
},
{
"path": "ch04/select/context.go",
"chars": 913,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n)\n\nfunc generateValues(ctx context.Context, counter chan int) {\n\tn := 1\n\tfor {\n"
},
{
"path": "ch04/select/main.go",
"chars": 1355,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"math/rand\"\n\t\"sync\"\n)\n\ntype (\n\tfibvalue struct {\n\t\tinput, value int\n\t}\n\tsquareval"
},
{
"path": "ch04/unbuffercounter/main.go",
"chars": 1068,
"preview": "// Example program with unbuffered channel\npackage main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\n// wg is used to wait for the progra"
},
{
"path": "ch04/unbuffercounter/main1.go",
"chars": 1167,
"preview": "// Example program with unbuffered channel\npackage main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\n// wg is used to wait for the progra"
},
{
"path": "ch04/worker/main.go",
"chars": 1649,
"preview": "// This sample program demonstrates how to use a buffered\n// channel to work on multiple tasks with a predefined number\n"
},
{
"path": "ch05/archivetar/main.go",
"chars": 3464,
"preview": "package main\n\nimport (\n\t\"archive/tar\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\n// addToArchive writes a given file into a .tar file\n"
},
{
"path": "ch05/archivezip/main.go",
"chars": 2540,
"preview": "package main\n\nimport (\n\t\"archive/zip\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\n// addToArchive writes a given file into a zip file.\n"
},
{
"path": "ch05/cmdflags/main.go",
"chars": 895,
"preview": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n)\n\nfunc main() {\n\n\tfileName := flag.String(\"filename\", \"logfile\", \"File name for t"
},
{
"path": "ch05/flag/main.go",
"chars": 609,
"preview": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n)\n\nfunc main() {\n\n\tstrPtr := flag.String(\"name\", \"Shiju\", \"a string\")\n\tnumbPtr := "
},
{
"path": "ch05/json/main.go",
"chars": 871,
"preview": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\n// Employee struct\ntype Employee struct {\n\tID "
},
{
"path": "ch05/jsontag/main.go",
"chars": 922,
"preview": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\n// Employee struct with struct tags\ntype Employee struct {\n\tID "
},
{
"path": "ch05/log/logger.go",
"chars": 1816,
"preview": "package main\n\nimport (\n\t\"io\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\nconst (\n\t// UNSPECIFIED logs nothing\n\tUNSPECIFIED Level = iota"
},
{
"path": "ch05/log/main.go",
"chars": 651,
"preview": "package main\n\nimport (\n\t\"errors\"\n\t\"flag\"\n)\n\nfunc main() {\n\t// Parse log level from command line\n\tlogLevel := flag.Int(\"l"
},
{
"path": "ch05/simplelog/main.go",
"chars": 1126,
"preview": "package main\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\n// Package level variables, which are pointer to log"
},
{
"path": "ch06/influx/main.go",
"chars": 3771,
"preview": "// Example demo for working with InfluxDB\npackage main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"math/rand\"\n\t\"time\"\n\n\tc"
},
{
"path": "ch06/mongo/bookmark_store.go",
"chars": 2115,
"preview": "package main\n\nimport (\n\t\"time\"\n\n\t\"gopkg.in/mgo.v2\"\n\t\"gopkg.in/mgo.v2/bson\"\n)\n\n// Bookmark type reperesents the metadata "
},
{
"path": "ch06/mongo/main.go",
"chars": 3291,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"time\"\n\n\t\"gopkg.in/mgo.v2\"\n)\n\nvar store BookmarkStore\nvar id string\n\n// init will "
},
{
"path": "ch06/postgres/main.go",
"chars": 2060,
"preview": "package main\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"log\"\n\n\t_ \"github.com/lib/pq\"\n)\n\n// Product struct provides the data mode"
},
{
"path": "ch06/rethink/bookmark_store.go",
"chars": 2242,
"preview": "package main\n\nimport (\n\t\"time\"\n\n\tr \"github.com/dancannon/gorethink\"\n)\n\n// Bookmark type reperesents the metadata of a bo"
},
{
"path": "ch06/rethink/main.go",
"chars": 3901,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"time\"\n\n\tr \"github.com/dancannon/gorethink\"\n)\n\nvar store BookmarkStore\nvar id stri"
},
{
"path": "ch07/bookmarkapi/common/auth.go",
"chars": 4920,
"preview": "package common\n\nimport (\n\t\"context\"\n\t\"crypto/rsa\"\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\tjwt \"gi"
},
{
"path": "ch07/bookmarkapi/common/bootstrapper.go",
"chars": 367,
"preview": "package common\n\n// StartUp bootstrapps the application\nfunc StartUp() {\n\t// Initialize AppConfig variable\n\tinitConfig()\n"
},
{
"path": "ch07/bookmarkapi/common/config.json",
"chars": 164,
"preview": "{\n \"Server\" : \"0.0.0.0:8080\",\n \"MongoDBHost\" : \"127.0.0.1\",\n \"MongoDBUser\"\t: \"\",\n \"MongoDBPwd\"\t: \"\",\n \"Databas"
},
{
"path": "ch07/bookmarkapi/common/logger.go",
"chars": 1818,
"preview": "package common\n\nimport (\n\t\"io\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\nconst (\n\t// UNSPECIFIED logs nothing\n\tUNSPECIFIED Level = io"
},
{
"path": "ch07/bookmarkapi/common/mongo_utils.go",
"chars": 1829,
"preview": "package common\n\nimport (\n\t\"log\"\n\t\"time\"\n\n\t\"gopkg.in/mgo.v2\"\n)\n\nvar session *mgo.Session\n\n// GetSession returns a MongoDB"
},
{
"path": "ch07/bookmarkapi/common/utils.go",
"chars": 1435,
"preview": "package common\n\nimport (\n\t\"encoding/json\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n)\n\ntype (\n\tappError struct {\n\t\tError string `jso"
},
{
"path": "ch07/bookmarkapi/controllers/bookmark_controller.go",
"chars": 5455,
"preview": "package controllers\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\t\"gopkg.in/mgo.v2\"\n\t\"gopkg.in/mgo."
},
{
"path": "ch07/bookmarkapi/controllers/resources.go",
"chars": 967,
"preview": "package controllers\n\nimport (\n\t\"github.com/shijuvar/go-recipes/ch07/bookmarkapi/model\"\n)\n\n//Models for JSON resources\nty"
},
{
"path": "ch07/bookmarkapi/controllers/user_controller.go",
"chars": 2462,
"preview": "package controllers\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/shijuvar/go-recipes/ch07/bookmarkapi/common\"\n\t\""
},
{
"path": "ch07/bookmarkapi/keys/app.rsa",
"chars": 887,
"preview": "-----BEGIN RSA PRIVATE KEY-----\nMIICWwIBAAKBgQDPSMNALgfEMEDbS3kCLiTlpx0S4tZH1jZLcGF5Pjhc9IuEIf7p\n6obYT1W7urDPWM8JGO1mdx+"
},
{
"path": "ch07/bookmarkapi/keys/app.rsa.pub",
"chars": 272,
"preview": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPSMNALgfEMEDbS3kCLiTlpx0S\n4tZH1jZLcGF5Pjhc9IuEIf7p6obY"
},
{
"path": "ch07/bookmarkapi/main.go",
"chars": 501,
"preview": "package main\n\nimport (\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/shijuvar/go-recipes/ch07/bookmarkapi/common\"\n\t\"github.com/shijuv"
},
{
"path": "ch07/bookmarkapi/model/models.go",
"chars": 883,
"preview": "package model\n\nimport (\n\t\"time\"\n\n\t\"gopkg.in/mgo.v2/bson\"\n)\n\ntype (\n\t// User type represents the registered user.\n\tUser s"
},
{
"path": "ch07/bookmarkapi/routers/bookmark.go",
"chars": 964,
"preview": "package routers\n\nimport (\n\t\"github.com/gorilla/mux\"\n\n\t\"github.com/shijuvar/go-recipes/ch07/bookmarkapi/common\"\n\t\"github."
},
{
"path": "ch07/bookmarkapi/routers/routers.go",
"chars": 340,
"preview": "package routers\n\nimport (\n\t\"github.com/gorilla/mux\"\n)\n\n// InitRoutes registers all routes for the application.\nfunc Init"
},
{
"path": "ch07/bookmarkapi/routers/user.go",
"chars": 376,
"preview": "package routers\n\nimport (\n\t\"github.com/shijuvar/go-recipes/ch07/bookmarkapi/controllers\"\n\n\t\"github.com/gorilla/mux\"\n)\n\n/"
},
{
"path": "ch07/bookmarkapi/store/bookmark_store.go",
"chars": 2285,
"preview": "package store\n\nimport (\n\t\"time\"\n\n\t\"gopkg.in/mgo.v2\"\n\t\"gopkg.in/mgo.v2/bson\"\n\n\t\"github.com/shijuvar/go-recipes/ch07/bookm"
},
{
"path": "ch07/bookmarkapi/store/user_store.go",
"chars": 975,
"preview": "package store\n\nimport (\n\t\"golang.org/x/crypto/bcrypt\"\n\t\"gopkg.in/mgo.v2\"\n\t\"gopkg.in/mgo.v2/bson\"\n\n\t\"github.com/shijuvar/"
},
{
"path": "ch07/customhandler/main.go",
"chars": 983,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\ntype textHandler struct {\n\tresponseText string\n}\n\nfunc (th *textHand"
},
{
"path": "ch07/defaultservemux/main.go",
"chars": 834,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc index(w http.ResponseWriter, r *http.Request) {\n\tw.Header().Set"
},
{
"path": "ch07/handlefunc/main.go",
"chars": 858,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc index(w http.ResponseWriter, r *http.Request) {\n\tw.Header().Set"
},
{
"path": "ch07/handlerfunc/main.go",
"chars": 1242,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n)\n\nfunc textResponseHandler(resposeText string) http.Handler {\n\treturn "
},
{
"path": "ch07/httpserver/main.go",
"chars": 217,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n)\n\nfunc handler(w http.ResponseWriter, r *http.Request) {\n\tfmt.Fprint(w, \"Hell"
},
{
"path": "ch07/middleware/main.go",
"chars": 1497,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"time\"\n)\n\n// loggingHandler is an HTTP Middleware that logs HTTP reque"
},
{
"path": "ch07/server/main.go",
"chars": 388,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc index(w http.ResponseWriter, r *http.Request) {\n\tfmt.Fp"
},
{
"path": "ch08/calc/calc.go",
"chars": 557,
"preview": "// Package calc provides a simple calculator\npackage calc\n\nimport \"math\"\n\n// Sum returns sum of integer values\nfunc Sum("
},
{
"path": "ch08/calc/calc_test.go",
"chars": 1875,
"preview": "package calc\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n)\n\n// Test case for the function Sum\nfunc TestSum(t *testing.T) {\n\tinpu"
},
{
"path": "ch08/httpbdd/controllers/controllers_suite_test.go",
"chars": 206,
"preview": "package controllers_test\n\nimport (\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n\n\t\"testing\"\n)\n\nfunc TestContr"
},
{
"path": "ch08/httpbdd/controllers/user_controller.go",
"chars": 1260,
"preview": "package controllers\n\nimport (\n\t\"encoding/json\"\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/shijuvar/go-recipes/ch08/httpbdd/model\"\n"
},
{
"path": "ch08/httpbdd/controllers/user_controller_test.go",
"chars": 3077,
"preview": "package controllers_test\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strings\"\n\n\t\"github.com/shijuvar/g"
},
{
"path": "ch08/httpbdd/main.go",
"chars": 488,
"preview": "package main\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\n\t\"github.com/shijuvar/go-recipes/ch08/httpbdd/controllers"
},
{
"path": "ch08/httpbdd/model/user.go",
"chars": 425,
"preview": "package model\n\nimport \"errors\"\n\n// ErrorEmailExists is an error value for duplicate email id\nvar ErrorEmailExists = erro"
},
{
"path": "ch08/httpbdd/store/user_store.go",
"chars": 1522,
"preview": "package store\n\nimport (\n\t\"log\"\n\t\"time\"\n\n\t\"gopkg.in/mgo.v2\"\n\t\"gopkg.in/mgo.v2/bson\"\n\n\t\"github.com/shijuvar/go-recipes/ch0"
},
{
"path": "ch08/httptest/main.go",
"chars": 868,
"preview": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n)\n\n// User model\ntype User struct {\n\tFirs"
},
{
"path": "ch08/httptest/main_test.go",
"chars": 1013,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/gorilla/mux\"\n)\n\n// TestGetUsers "
},
{
"path": "grpc/client/main.go",
"chars": 2571,
"preview": "package main\n\nimport (\n\t\"io\"\n\t\"log\"\n\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/grpc\"\n\n\tpb \"github.com/shijuvar/go-"
},
{
"path": "grpc/customer/customer.pb.go",
"chars": 10209,
"preview": "// Code generated by protoc-gen-go.\n// source: customer.proto\n// DO NOT EDIT!\n\n/*\nPackage customer is a generated protoc"
},
{
"path": "grpc/customer/customer.proto",
"chars": 839,
"preview": "syntax = \"proto3\";\npackage customer;\n\n\n// The Customer service definition.\nservice Customer { \n // Get all Customers "
},
{
"path": "grpc/server/main.go",
"chars": 1183,
"preview": "package main\n\nimport (\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n\n\t\"golang.org/x/net/context\"\n\t\"google.golang.org/grpc\"\n\n\tpb \"github.com/"
}
]
About this extraction
This page contains the full source code of the shijuvar/go-recipes GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 103 files (119.6 KB), approximately 37.9k tokens, and a symbol index with 362 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.