SlideShare a Scribd company logo
GO WEB
DEVELOPMENT 101
3 MONTHS to be productive
74% write API SERVICES
45% write WEB APPS
*
Go Developer Survey 2020 Results
entwickler.de Go Day: Go Web Development 101
HELLO GOPHER
package main



import "fmt"



func main() {

fmt.Println("Hello Gopher!")
}
Run Code
go build hellogopher.go // 1. Compile code

./hellogopher // 2. Run binary
go run hellogopher.go // Compile code + run binary
DEVELOPMENT
JetBrains
GoLand
Visual
Studio Code
Vim Go
5 FACTS ABOUT GO
1 static type system
2 garbage collection
3 no inheritance
4 built-in concurrency
5 native execution 

Linux,
Win, z/OS, 386, amd64, ARM, wasm, ...
VARIABLES, SLICES, LOOPS
// Variable
var kitty string = "Kitty"
bella := "Bella"
1
2
3
4
// Array (fixed length)
5
namesArray := [3]string{kitty, bella, "Cleo"}
6
7
// Slice (variable length)
8
namesSlice := make([]string, 2)
9
namesSlice[0] = kitty
10
11
// Loop
12
for i, name := range namesSlice {
13
fmt.Println("Hello " + name + "!")
14
}
15
// Array (fixed length)
namesArray := [3]string{kitty, bella, "Cleo"}
// Variable
1
var kitty string = "Kitty"
2
bella := "Bella"
3
4
5
6
7
// Slice (variable length)
8
namesSlice := make([]string, 2)
9
namesSlice[0] = kitty
10
11
// Loop
12
for i, name := range namesSlice {
13
fmt.Println("Hello " + name + "!")
14
}
15
// Slice (variable length)
namesSlice := make([]string, 2)
namesSlice[0] = kitty
// Variable
1
var kitty string = "Kitty"
2
bella := "Bella"
3
4
// Array (fixed length)
5
namesArray := [3]string{kitty, bella, "Cleo"}
6
7
8
9
10
11
// Loop
12
for i, name := range namesSlice {
13
fmt.Println("Hello " + name + "!")
14
}
15
// Loop
for i, name := range namesSlice {
fmt.Println("Hello " + name + "!")
}
// Variable
1
var kitty string = "Kitty"
2
bella := "Bella"
3
4
// Array (fixed length)
5
namesArray := [3]string{kitty, bella, "Cleo"}
6
7
// Slice (variable length)
8
namesSlice := make([]string, 2)
9
namesSlice[0] = kitty
10
11
12
13
14
15
STRUCT
type Cat struct {
Name string
}
1
2
3
4
func main() {
5
c := Cat{Name: "Kitty"}
6
fmt.Println("Hello " + c.Name + "!")
7
}
8
c := Cat{Name: "Kitty"}
fmt.Println("Hello " + c.Name + "!")
type Cat struct {
1
Name string
2
}
3
4
func main() {
5
6
7
}
8
type Cat struct {
Name string
}
func main() {
c := Cat{Name: "Kitty"}
fmt.Println("Hello " + c.Name + "!")
}
1
2
3
4
5
6
7
8
ERRORS
// Error as return value
func (c Cat) feed(food string) error {
if c.Name == "Kitty" && food != "Steak Tartare" {
return errors.New("Won't eat!")
}
return nil
}
1
2
3
4
5
6
7
8
func main() {
9
c := Cat{Name: "Kitty"}
10
11
// Handle error
12
err := c.feed("Caviar")
13
if err != nil {
14
fmt.Printf("%v won't eat it.", c.Name)
15
}
16
}
17
// Handle error
err := c.feed("Caviar")
if err != nil {
fmt.Printf("%v won't eat it.", c.Name)
}
}
// Error as return value
1
func (c Cat) feed(food string) error {
2
if c.Name == "Kitty" && food != "Steak Tartare" {
3
return errors.New("Won't eat!")
4
}
5
return nil
6
}
7
8
func main() {
9
c := Cat{Name: "Kitty"}
10
11
12
13
14
15
16
17
THE CATS APP
entwickler.de Go Day: Go Web Development 101
CATS APP 

API
SET UP CATS APP
# Create directory

mkdir cats

cd cats
# Enable dependency tracking

go mod init goday.com/cats
# Create go file

touch main.go
CAT API SIMPLE
func main() {
http.HandleFunc("/api/cats", catAPIHandler)
http.ListenAndServe(":8080", nil)
}
func catAPIHandler(w http.ResponseWriter, r *http.Request)
1
fmt.Fprintf(w, "Meow!")
2
w.WriteHeader(http.StatusOK)
3
}
4
5
6
7
8
9
func catAPIHandler(w http.ResponseWriter, r *http.Request)
fmt.Fprintf(w, "Meow!")
w.WriteHeader(http.StatusOK)
}
1
2
3
4
5
func main() {
6
http.HandleFunc("/api/cats", catAPIHandler)
7
http.ListenAndServe(":8080", nil)
8
}
9
CAT API WITH JSON
func catAPIHandler(w http.ResponseWriter, r *http.Request) {
cats := make([]Cat, 1)
cats[0] = Cat{Name: "Ginger"}
json.NewEncoder(w).Encode(c)
type Cat struct {
1
Name string
2
}
3
4
5
6
7
8
}
9
10
func main() {
11
http.HandleFunc("/api/cats", catAPIHandler)
12
http.ListenAndServe(":8080", nil)
13
}
14
type Cat struct {
Name string
}
1
2
3
4
func catAPIHandler(w http.ResponseWriter, r *http.Request) {
5
cats := make([]Cat, 1)
6
cats[0] = Cat{Name: "Ginger"}
7
json.NewEncoder(w).Encode(c)
8
}
9
10
func main() {
11
http.HandleFunc("/api/cats", catAPIHandler)
12
http.ListenAndServe(":8080", nil)
13
}
14
type Cat struct {
Name string
}
func catAPIHandler(w http.ResponseWriter, r *http.Request) {
cats := make([]Cat, 1)
cats[0] = Cat{Name: "Ginger"}
json.NewEncoder(w).Encode(c)
1
2
3
4
5
6
7
8
}
9
10
func main() {
11
http.HandleFunc("/api/cats", catAPIHandler)
12
http.ListenAndServe(":8080", nil)
13
}
14
type Cat struct {
Name string
}
func catAPIHandler(w http.ResponseWriter, r *http.Request) {
cats := make([]Cat, 1)
cats[0] = Cat{Name: "Ginger"}
json.NewEncoder(w).Encode(c)
}
func main() {
http.HandleFunc("/api/cats", catAPIHandler)
http.ListenAndServe(":8080", nil)
1
2
3
4
5
6
7
8
9
10
11
12
13
}
14
CAT API WITH JSON
# Query cat API
curl -s http://localhost:8080/api/cats | jq
1
2
[
3
{
4
"Name": "Ginger"
5
}
6
]
7
[
{
"Name": "Ginger"
}
]
# Query cat API
1
curl -s http://localhost:8080/api/cats | jq
2
3
4
5
6
7
CAT API WITH JSON
type Cat struct {
Name string
}
func catAPIHandler(w http.ResponseWriter, r *http.Request) {
cats := make([]Cat, 1)
cats[0] = Cat{Name: "Ginger"}
json.NewEncoder(w).Encode(cats)
1
2 `json:"name"`
3
4
5
6
7
8
}
9
10
func main() {
11
http.HandleFunc("/api/cats", catAPIHandler)
12
http.ListenAndServe(":8080", nil)
13
}
14
TEST CAT API cat_api_test.go
func TestCatAPIHandler(t *testing.T) {
}
1
// 1. Create test request
2
req, _ := http.NewRequest("GET", "/api/cats", nil)
3
4
// 2. Create recorder (which satisfies http.ResponseWriter)
5
recorder := httptest.NewRecorder()
6
7
// 3. Invoke handler
8
catAPIHandler(recorder, req)
9
10
// 4. Check the response
11
if recorder.Code != http.StatusOK {
12
t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.Sta
13
}
14
15
// 1. Create test request
req, _ := http.NewRequest("GET", "/api/cats", nil)
func TestCatAPIHandler(t *testing.T) {
1
2
3
4
// 2. Create recorder (which satisfies http.ResponseWriter)
5
recorder := httptest.NewRecorder()
6
7
// 3. Invoke handler
8
catAPIHandler(recorder, req)
9
10
// 4. Check the response
11
if recorder.Code != http.StatusOK {
12
t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.Sta
13
}
14
}
15
// 2. Create recorder (which satisfies http.ResponseWriter)
recorder := httptest.NewRecorder()
func TestCatAPIHandler(t *testing.T) {
1
// 1. Create test request
2
req, _ := http.NewRequest("GET", "/api/cats", nil)
3
4
5
6
7
// 3. Invoke handler
8
catAPIHandler(recorder, req)
9
10
// 4. Check the response
11
if recorder.Code != http.StatusOK {
12
t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.Sta
13
}
14
}
15
// 3. Invoke handler
catAPIHandler(recorder, req)
func TestCatAPIHandler(t *testing.T) {
1
// 1. Create test request
2
req, _ := http.NewRequest("GET", "/api/cats", nil)
3
4
// 2. Create recorder (which satisfies http.ResponseWriter)
5
recorder := httptest.NewRecorder()
6
7
8
9
10
// 4. Check the response
11
if recorder.Code != http.StatusOK {
12
t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.Sta
13
}
14
}
15
// 4. Check the response
if recorder.Code != http.StatusOK {
t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.Sta
}
func TestCatAPIHandler(t *testing.T) {
1
// 1. Create test request
2
req, _ := http.NewRequest("GET", "/api/cats", nil)
3
4
// 2. Create recorder (which satisfies http.ResponseWriter)
5
recorder := httptest.NewRecorder()
6
7
// 3. Invoke handler
8
catAPIHandler(recorder, req)
9
10
11
12
13
14
}
15
func TestCatAPIHandler(t *testing.T) {
// 1. Create test request
req, _ := http.NewRequest("GET", "/api/cats", nil)
// 2. Create recorder (which satisfies http.ResponseWriter)
recorder := httptest.NewRecorder()
// 3. Invoke handler
catAPIHandler(recorder, req)
// 4. Check the response
if recorder.Code != http.StatusOK {
t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.Sta
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
RUN TEST
# Run tests
go test -v ./...
1
2
=== RUN TestCatAPIHandler
3
--- PASS: TestCatAPIHandler (0.00s)
4
PASS
5
coverage: 50.0% of statements
6
ok devopscon.com/cats 0.127s coverage: 50.0% of stateme
7
=== RUN TestCatAPIHandler
--- PASS: TestCatAPIHandler (0.00s)
PASS
coverage: 50.0% of statements
ok devopscon.com/cats 0.127s coverage: 50.0% of statem
# Run tests
1
go test -v ./...
2
3
4
5
6
7
BUILD WITH Makefile
build:
go build -o dist/"${BIN_FILE}"
.DEFAULT_GOAL := build
1
BIN_FILE=cats
2
3
4
5
6
test:
7
go test -v ./...
8
9
run:
10
./"${BIN_FILE}"
11
12
clean:
13
go clean
14
test:
go test -v ./...
.DEFAULT_GOAL := build
1
BIN_FILE=cats
2
3
build:
4
go build -o dist/"${BIN_FILE}"
5
6
7
8
9
run:
10
./"${BIN_FILE}"
11
12
clean:
13
go clean
14
run:
./"${BIN_FILE}"
.DEFAULT_GOAL := build
1
BIN_FILE=cats
2
3
build:
4
go build -o dist/"${BIN_FILE}"
5
6
test:
7
go test -v ./...
8
9
10
11
12
clean:
13
go clean
14
clean:
go clean
.DEFAULT_GOAL := build
1
BIN_FILE=cats
2
3
build:
4
go build -o dist/"${BIN_FILE}"
5
6
test:
7
go test -v ./...
8
9
run:
10
./"${BIN_FILE}"
11
12
13
14
.DEFAULT_GOAL := build
BIN_FILE=cats
build:
go build -o dist/"${BIN_FILE}"
test:
go test -v ./...
run:
./"${BIN_FILE}"
clean:
go clean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
DEMO
CATS APP 

WEB
CATS HANDLER BASIC TEMPLATE SETUP
func indexHandler(w http.ResponseWriter, r *http.Request) {
var tpl = template.Must(template.ParseFiles("index.html"))
tpl.Execute(w, nil)
1
2
3
}
4
5
func main() {
6
http.HandleFunc("/", indexHandler)
7
http.ListenAndServe(":8080", nil)
8
}
9
func indexHandler(w http.ResponseWriter, r *http.Request) {
var tpl = template.Must(template.ParseFiles("index.html"))
tpl.Execute(w, nil)
}
func main() {
http.HandleFunc("/", indexHandler)
http.ListenAndServe(":8080", nil)
}
1
2
3
4
5
6
7
8
9
func indexHandler(w http.ResponseWriter, r *http.Request) {
var tpl = template.Must(template.ParseFiles("index.html"))
tpl.Execute(w, nil)
}
func main() {
http.HandleFunc("/", indexHandler)
http.ListenAndServe(":8080", nil)
}
1
2
3
4
5
6
7
8
9
CATS HANDLER WITH MULTIPLEXER
mux := http.NewServeMux()
mux.HandleFunc("/", indexHandler)
func indexHandler(w http.ResponseWriter, r *http.Request) {
1
var tpl = template.Must(template.ParseFiles("index.html"))
2
tpl.Execute(w, nil)
3
}
4
5
func main() {
6
7
8
9
http.ListenAndServe(":8080", mux)
10
}
11
http.ListenAndServe(":8080", mux)
func indexHandler(w http.ResponseWriter, r *http.Request) {
1
var tpl = template.Must(template.ParseFiles("index.html"))
2
tpl.Execute(w, nil)
3
}
4
5
func main() {
6
mux := http.NewServeMux()
7
mux.HandleFunc("/", indexHandler)
8
9
10
}
11
func indexHandler(w http.ResponseWriter, r *http.Request) {
var tpl = template.Must(template.ParseFiles("index.html"))
tpl.Execute(w, nil)
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", indexHandler)
http.ListenAndServe(":8080", mux)
}
1
2
3
4
5
6
7
8
9
10
11
SERVE FILES FROM FILESYSTEM
// Serve files
fs := http.FileServer(http.Dir("assets"))
mux.Handle("/assets/", http.StripPrefix("/assets/", fs))
func main() {
1
mux := http.NewServeMux()
2
mux.HandleFunc("/", indexHandler)
3
4
5
6
7
8
http.ListenAndServe(":8080", mux)
9
}
10
SERVE FILES EMBEDDED IN BINARY
// Serve files
mux.Handle("/assets/", http.FileServer(http.FS(assets)))
//go:embed assets
1
var assets embed.FS
2
3
func main() {
4
mux := http.NewServeMux()
5
mux.HandleFunc("/", indexHandler)
6
7
8
9
10
http.ListenAndServe(":8080", mux)
11
}
12
//go:embed assets
var assets embed.FS
// Serve files
mux.Handle("/assets/", http.FileServer(http.FS(assets)))
1
2
3
func main() {
4
mux := http.NewServeMux()
5
mux.HandleFunc("/", indexHandler)
6
7
8
9
10
http.ListenAndServe(":8080", mux)
11
}
12
mux.HandleFunc("/", indexHandler)
mux.Handle("/assets/", http.FileServer(http.FS(assets)))
//go:embed assets
1
var assets embed.FS
2
3
func main() {
4
mux := http.NewServeMux()
5
6
7
// Serve files
8
9
10
http.ListenAndServe(":8080", mux)
11
}
12
HANDLER AND HANDLEFUNC
CATS HANDLER TEMPLATE WITH DATA
main.go
type Cat struct {

Name string

}



func indexHandler(w ResponseWriter, r *Request) {
// Create cat slice

cat := make([]Cat, 1)



// Add cat ginger

cat[0] = Cat{Name: "Ginger"}



// Render template

tpl.Execute(w, cat)

}
index.html
<body>

<h1>Cats App</h1>

{{ range. }}

<h2>{{ .Name }}</h2>
{{ end }}

</body>
entwickler.de Go Day: Go Web Development 101
CATS HANDLER WITH CATS API
Query Cats API
GET https://api.thecatapi.com/v1/breeds?limit=5
[

{

"id": "abys",

"name": "Abyssinian",

"image": {

"url": "https://cdn2.thecatapi.com/images/0XYvRd7oD.jpg
}

},

{

"id": "aege",

"name": "Aegean",

"image": {

"url": "https://cdn2.thecatapi.com/images/ozEvzdVM-.jpg
}

},

...

]
Map JSON
type Cat struct {

ID string `json:"id"`

Name string `json:"name"`

Image struct {

URL string `json:"url"`

} `json:"image"`

}
entwickler.de Go Day: Go Web Development 101
CATS HANDLER WITH CATS API
resp, err := http.Get("https://api.thecatapi.com/v1/breeds?limit=5")
if err != nil {
http.Error(w, "Cats API error", http.StatusInternalServerError)
return
}
func indexHandler(w http.ResponseWriter, r *http.Request) {
1
2
3
4
5
6
7
// Create cat slice
8
cat := make([]Cat, 5)
9
10
// Read and parse body
11
defer resp.Body.Close()
12
body, _ := ioutil.ReadAll(resp.Body)
13
json.Unmarshal(body, &cat)
14
15
tpl.Execute(w, cat)
16
}
17
// Create cat slice
cat := make([]Cat, 5)
func indexHandler(w http.ResponseWriter, r *http.Request) {
1
resp, err := http.Get("https://api.thecatapi.com/v1/breeds?limit=5")
2
if err != nil {
3
http.Error(w, "Cats API error", http.StatusInternalServerError)
4
return
5
}
6
7
8
9
10
// Read and parse body
11
defer resp.Body.Close()
12
body, _ := ioutil.ReadAll(resp.Body)
13
json.Unmarshal(body, &cat)
14
15
tpl.Execute(w, cat)
16
}
17
// Read and parse body
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
json.Unmarshal(body, &cat)
func indexHandler(w http.ResponseWriter, r *http.Request) {
1
resp, err := http.Get("https://api.thecatapi.com/v1/breeds?limit=5")
2
if err != nil {
3
http.Error(w, "Cats API error", http.StatusInternalServerError)
4
return
5
}
6
7
// Create cat slice
8
cat := make([]Cat, 5)
9
10
11
12
13
14
15
tpl.Execute(w, cat)
16
}
17
func indexHandler(w http.ResponseWriter, r *http.Request) {
resp, err := http.Get("https://api.thecatapi.com/v1/breeds?limit=5")
if err != nil {
http.Error(w, "Cats API error", http.StatusInternalServerError)
return
}
// Create cat slice
cat := make([]Cat, 5)
// Read and parse body
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
json.Unmarshal(body, &cat)
tpl.Execute(w, cat)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
MIDDLEWARE
cross cutting functionality for all requests 

(e.g. logging, authentication)
#
create a chain of handlers 

router => middleware handler => application handler
#
satisfy the interface http.Handler
#
MIDDLEWARE TO LOG REQUESTS
http.ListenAndServe(":8080", loggingMiddleware(mux))
func loggingMiddleware(next http.Handler) http.Handler {
1
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Reque
2
log.Printf("%v requested URL %v", r.Host, r.URL)
3
next.ServeHTTP(w, r)
4
})
5
}
6
7
func main() {
8
mux := http.NewServeMux()
9
mux.HandleFunc("/", indexHandler)
10
11
12
}
13
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Reque
log.Printf("%v requested URL %v", r.Host, r.URL)
next.ServeHTTP(w, r)
})
}
1
2
3
4
5
6
7
func main() {
8
mux := http.NewServeMux()
9
mux.HandleFunc("/", indexHandler)
10
11
http.ListenAndServe(":8080", loggingMiddleware(mux))
12
}
13
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Reque
log.Printf("%v requested URL %v", r.Host, r.URL)
next.ServeHTTP(w, r)
})
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", indexHandler)
http.ListenAndServe(":8080", loggingMiddleware(mux))
1
2
3
4
5
6
7
8
9
10
11
12
}
13
DEMO
BASICS 

 
Dev Setup
Variables,
Slices, Loops
Struct
Errors
#
#
#
#
CATS APP 

API
Handler (with
JSON)
Http Test
Build
#
#
#
CATS APP 

WEB
Multiplexer
(Router)
File Server
Template
Middleware
#
#
#
#
entwickler.de Go Day: Go Web Development 101
JAN STAMER
Solution Architect
jan.stamer@comdirect.de

More Related Content

PDF
betterCode() Go: Einstieg in Go, Standard-Library und Ökosystem
PDF
JavaForum Nord 2021: Java to Go - Google Go für Java-Entwickler
PDF
The Magnificent Seven
PDF
Clojure 1.1 And Beyond
ODP
Nigel hamilton-megameet-2013
ODP
Rust言語紹介
PDF
Hello Swift 3/5 - Function
PPTX
Gevent rabbit rpc
betterCode() Go: Einstieg in Go, Standard-Library und Ökosystem
JavaForum Nord 2021: Java to Go - Google Go für Java-Entwickler
The Magnificent Seven
Clojure 1.1 And Beyond
Nigel hamilton-megameet-2013
Rust言語紹介
Hello Swift 3/5 - Function
Gevent rabbit rpc

What's hot (20)

PDF
Email Using Plsql
PDF
The Ring programming language version 1.5.3 book - Part 25 of 184
PDF
uerj201212
PDF
Cooking pies with Celery
PDF
Are we ready to Go?
PDF
clap: Command line argument parser for Pharo
PDF
OSDC.TW - Gutscript for PHP haters
PDF
Fun with Ruby and Cocoa
PPTX
Dts x dicoding #2 memulai pemrograman kotlin
PPTX
Introducing to Asynchronous Programming
PPT
2016年のPerl (Long version)
PDF
Go ahead, make my day
PPT
Unix Programming with Perl 2
PDF
ssh.isdn.test
PDF
Code Generation in PHP - PHPConf 2015
PDF
The Ring programming language version 1.9 book - Part 37 of 210
PDF
General Functions
TXT
Assignment6
PPTX
Project in programming
Email Using Plsql
The Ring programming language version 1.5.3 book - Part 25 of 184
uerj201212
Cooking pies with Celery
Are we ready to Go?
clap: Command line argument parser for Pharo
OSDC.TW - Gutscript for PHP haters
Fun with Ruby and Cocoa
Dts x dicoding #2 memulai pemrograman kotlin
Introducing to Asynchronous Programming
2016年のPerl (Long version)
Go ahead, make my day
Unix Programming with Perl 2
ssh.isdn.test
Code Generation in PHP - PHPConf 2015
The Ring programming language version 1.9 book - Part 37 of 210
General Functions
Assignment6
Project in programming
Ad

Similar to entwickler.de Go Day: Go Web Development 101 (20)

PDF
DevOpsCon 2021: Go Web Development 101
PDF
Geeks Anonymes - Le langage Go
PPTX
Golang basics for Java developers - Part 1
PDF
外部環境への依存をテストする
PDF
Let's Go-lang
PDF
Go for Rubyists
PDF
To GO or not to GO
PDF
Learning go for perl programmers
KEY
Beauty and Power of Go
PDF
Go serving: Building server app with go
PDF
10〜30分で何となく分かるGo
PDF
Writing Go(od) Tests (FOSDEM 2020)
PDF
Golang and Eco-System Introduction / Overview
PPTX
EuroPython 2016 - Do I Need To Switch To Golang
PPT
go.ppt
PDF
Golang勉強会
PPTX
Golang iran - tutorial go programming language - Preliminary
PDF
An Introduction to Go
PPTX
Net/http and the http.handler interface
DevOpsCon 2021: Go Web Development 101
Geeks Anonymes - Le langage Go
Golang basics for Java developers - Part 1
外部環境への依存をテストする
Let's Go-lang
Go for Rubyists
To GO or not to GO
Learning go for perl programmers
Beauty and Power of Go
Go serving: Building server app with go
10〜30分で何となく分かるGo
Writing Go(od) Tests (FOSDEM 2020)
Golang and Eco-System Introduction / Overview
EuroPython 2016 - Do I Need To Switch To Golang
go.ppt
Golang勉強会
Golang iran - tutorial go programming language - Preliminary
An Introduction to Go
Net/http and the http.handler interface
Ad

More from Jan Stamer (13)

PDF
JAX 2025: Microservices lieben Azure Container Apps
PDF
JAX 2025: Go Crashkurs mit praktischen Beispielen
PDF
W-JAX 2024: Go in der Praxis, für CLI und Web
PDF
W-JAX 2024: Serverless mit Go in der Cloud
PDF
JAX 2024: Go-über-den-Wolken und in der Cloud
PDF
JAX 2024: Go in der Praxis einsetzen
PDF
W-JAX 2023: Go über den Wolken
PDF
CloudLand 2023: Rock, Paper, Scissors Cloud Competition - Go vs. Java
PDF
entwickler.de 05/2023: Go über den Wolken
PDF
IT-Tage 2021: Java to Go - Google Go für Java-Entwickler
PDF
JCON 2021: Turbo powered Web Apps
PDF
Karlsruher Entwicklertag 2021: Turbo powered Web Apps
PDF
Jugs HH: Elefant unter Strom - von OldSQL über NoSQL zu NewSQL?
JAX 2025: Microservices lieben Azure Container Apps
JAX 2025: Go Crashkurs mit praktischen Beispielen
W-JAX 2024: Go in der Praxis, für CLI und Web
W-JAX 2024: Serverless mit Go in der Cloud
JAX 2024: Go-über-den-Wolken und in der Cloud
JAX 2024: Go in der Praxis einsetzen
W-JAX 2023: Go über den Wolken
CloudLand 2023: Rock, Paper, Scissors Cloud Competition - Go vs. Java
entwickler.de 05/2023: Go über den Wolken
IT-Tage 2021: Java to Go - Google Go für Java-Entwickler
JCON 2021: Turbo powered Web Apps
Karlsruher Entwicklertag 2021: Turbo powered Web Apps
Jugs HH: Elefant unter Strom - von OldSQL über NoSQL zu NewSQL?

Recently uploaded (20)

PDF
Accuracy of neural networks in brain wave diagnosis of schizophrenia
PDF
Encapsulation theory and applications.pdf
PDF
1 - Historical Antecedents, Social Consideration.pdf
PDF
gpt5_lecture_notes_comprehensive_20250812015547.pdf
PDF
ENT215_Completing-a-large-scale-migration-and-modernization-with-AWS.pdf
PDF
Heart disease approach using modified random forest and particle swarm optimi...
PDF
Video forgery: An extensive analysis of inter-and intra-frame manipulation al...
PPTX
cloud_computing_Infrastucture_as_cloud_p
PDF
A novel scalable deep ensemble learning framework for big data classification...
PDF
Hybrid model detection and classification of lung cancer
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PPTX
Tartificialntelligence_presentation.pptx
PDF
Hindi spoken digit analysis for native and non-native speakers
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PPTX
A Presentation on Artificial Intelligence
PDF
A comparative analysis of optical character recognition models for extracting...
PDF
Mushroom cultivation and it's methods.pdf
PPTX
TechTalks-8-2019-Service-Management-ITIL-Refresh-ITIL-4-Framework-Supports-Ou...
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PPTX
Chapter 5: Probability Theory and Statistics
Accuracy of neural networks in brain wave diagnosis of schizophrenia
Encapsulation theory and applications.pdf
1 - Historical Antecedents, Social Consideration.pdf
gpt5_lecture_notes_comprehensive_20250812015547.pdf
ENT215_Completing-a-large-scale-migration-and-modernization-with-AWS.pdf
Heart disease approach using modified random forest and particle swarm optimi...
Video forgery: An extensive analysis of inter-and intra-frame manipulation al...
cloud_computing_Infrastucture_as_cloud_p
A novel scalable deep ensemble learning framework for big data classification...
Hybrid model detection and classification of lung cancer
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Tartificialntelligence_presentation.pptx
Hindi spoken digit analysis for native and non-native speakers
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
A Presentation on Artificial Intelligence
A comparative analysis of optical character recognition models for extracting...
Mushroom cultivation and it's methods.pdf
TechTalks-8-2019-Service-Management-ITIL-Refresh-ITIL-4-Framework-Supports-Ou...
MIND Revenue Release Quarter 2 2025 Press Release
Chapter 5: Probability Theory and Statistics

entwickler.de Go Day: Go Web Development 101

  • 2. 3 MONTHS to be productive 74% write API SERVICES 45% write WEB APPS * Go Developer Survey 2020 Results
  • 4. HELLO GOPHER package main import "fmt" func main() { fmt.Println("Hello Gopher!") } Run Code go build hellogopher.go // 1. Compile code ./hellogopher // 2. Run binary go run hellogopher.go // Compile code + run binary
  • 6. 5 FACTS ABOUT GO 1 static type system 2 garbage collection 3 no inheritance 4 built-in concurrency 5 native execution Linux, Win, z/OS, 386, amd64, ARM, wasm, ...
  • 7. VARIABLES, SLICES, LOOPS // Variable var kitty string = "Kitty" bella := "Bella" 1 2 3 4 // Array (fixed length) 5 namesArray := [3]string{kitty, bella, "Cleo"} 6 7 // Slice (variable length) 8 namesSlice := make([]string, 2) 9 namesSlice[0] = kitty 10 11 // Loop 12 for i, name := range namesSlice { 13 fmt.Println("Hello " + name + "!") 14 } 15 // Array (fixed length) namesArray := [3]string{kitty, bella, "Cleo"} // Variable 1 var kitty string = "Kitty" 2 bella := "Bella" 3 4 5 6 7 // Slice (variable length) 8 namesSlice := make([]string, 2) 9 namesSlice[0] = kitty 10 11 // Loop 12 for i, name := range namesSlice { 13 fmt.Println("Hello " + name + "!") 14 } 15 // Slice (variable length) namesSlice := make([]string, 2) namesSlice[0] = kitty // Variable 1 var kitty string = "Kitty" 2 bella := "Bella" 3 4 // Array (fixed length) 5 namesArray := [3]string{kitty, bella, "Cleo"} 6 7 8 9 10 11 // Loop 12 for i, name := range namesSlice { 13 fmt.Println("Hello " + name + "!") 14 } 15 // Loop for i, name := range namesSlice { fmt.Println("Hello " + name + "!") } // Variable 1 var kitty string = "Kitty" 2 bella := "Bella" 3 4 // Array (fixed length) 5 namesArray := [3]string{kitty, bella, "Cleo"} 6 7 // Slice (variable length) 8 namesSlice := make([]string, 2) 9 namesSlice[0] = kitty 10 11 12 13 14 15
  • 8. STRUCT type Cat struct { Name string } 1 2 3 4 func main() { 5 c := Cat{Name: "Kitty"} 6 fmt.Println("Hello " + c.Name + "!") 7 } 8 c := Cat{Name: "Kitty"} fmt.Println("Hello " + c.Name + "!") type Cat struct { 1 Name string 2 } 3 4 func main() { 5 6 7 } 8 type Cat struct { Name string } func main() { c := Cat{Name: "Kitty"} fmt.Println("Hello " + c.Name + "!") } 1 2 3 4 5 6 7 8
  • 9. ERRORS // Error as return value func (c Cat) feed(food string) error { if c.Name == "Kitty" && food != "Steak Tartare" { return errors.New("Won't eat!") } return nil } 1 2 3 4 5 6 7 8 func main() { 9 c := Cat{Name: "Kitty"} 10 11 // Handle error 12 err := c.feed("Caviar") 13 if err != nil { 14 fmt.Printf("%v won't eat it.", c.Name) 15 } 16 } 17 // Handle error err := c.feed("Caviar") if err != nil { fmt.Printf("%v won't eat it.", c.Name) } } // Error as return value 1 func (c Cat) feed(food string) error { 2 if c.Name == "Kitty" && food != "Steak Tartare" { 3 return errors.New("Won't eat!") 4 } 5 return nil 6 } 7 8 func main() { 9 c := Cat{Name: "Kitty"} 10 11 12 13 14 15 16 17
  • 13. SET UP CATS APP # Create directory mkdir cats cd cats # Enable dependency tracking go mod init goday.com/cats # Create go file touch main.go
  • 14. CAT API SIMPLE func main() { http.HandleFunc("/api/cats", catAPIHandler) http.ListenAndServe(":8080", nil) } func catAPIHandler(w http.ResponseWriter, r *http.Request) 1 fmt.Fprintf(w, "Meow!") 2 w.WriteHeader(http.StatusOK) 3 } 4 5 6 7 8 9 func catAPIHandler(w http.ResponseWriter, r *http.Request) fmt.Fprintf(w, "Meow!") w.WriteHeader(http.StatusOK) } 1 2 3 4 5 func main() { 6 http.HandleFunc("/api/cats", catAPIHandler) 7 http.ListenAndServe(":8080", nil) 8 } 9
  • 15. CAT API WITH JSON func catAPIHandler(w http.ResponseWriter, r *http.Request) { cats := make([]Cat, 1) cats[0] = Cat{Name: "Ginger"} json.NewEncoder(w).Encode(c) type Cat struct { 1 Name string 2 } 3 4 5 6 7 8 } 9 10 func main() { 11 http.HandleFunc("/api/cats", catAPIHandler) 12 http.ListenAndServe(":8080", nil) 13 } 14 type Cat struct { Name string } 1 2 3 4 func catAPIHandler(w http.ResponseWriter, r *http.Request) { 5 cats := make([]Cat, 1) 6 cats[0] = Cat{Name: "Ginger"} 7 json.NewEncoder(w).Encode(c) 8 } 9 10 func main() { 11 http.HandleFunc("/api/cats", catAPIHandler) 12 http.ListenAndServe(":8080", nil) 13 } 14 type Cat struct { Name string } func catAPIHandler(w http.ResponseWriter, r *http.Request) { cats := make([]Cat, 1) cats[0] = Cat{Name: "Ginger"} json.NewEncoder(w).Encode(c) 1 2 3 4 5 6 7 8 } 9 10 func main() { 11 http.HandleFunc("/api/cats", catAPIHandler) 12 http.ListenAndServe(":8080", nil) 13 } 14 type Cat struct { Name string } func catAPIHandler(w http.ResponseWriter, r *http.Request) { cats := make([]Cat, 1) cats[0] = Cat{Name: "Ginger"} json.NewEncoder(w).Encode(c) } func main() { http.HandleFunc("/api/cats", catAPIHandler) http.ListenAndServe(":8080", nil) 1 2 3 4 5 6 7 8 9 10 11 12 13 } 14
  • 16. CAT API WITH JSON # Query cat API curl -s http://localhost:8080/api/cats | jq 1 2 [ 3 { 4 "Name": "Ginger" 5 } 6 ] 7 [ { "Name": "Ginger" } ] # Query cat API 1 curl -s http://localhost:8080/api/cats | jq 2 3 4 5 6 7
  • 17. CAT API WITH JSON type Cat struct { Name string } func catAPIHandler(w http.ResponseWriter, r *http.Request) { cats := make([]Cat, 1) cats[0] = Cat{Name: "Ginger"} json.NewEncoder(w).Encode(cats) 1 2 `json:"name"` 3 4 5 6 7 8 } 9 10 func main() { 11 http.HandleFunc("/api/cats", catAPIHandler) 12 http.ListenAndServe(":8080", nil) 13 } 14
  • 18. TEST CAT API cat_api_test.go func TestCatAPIHandler(t *testing.T) { } 1 // 1. Create test request 2 req, _ := http.NewRequest("GET", "/api/cats", nil) 3 4 // 2. Create recorder (which satisfies http.ResponseWriter) 5 recorder := httptest.NewRecorder() 6 7 // 3. Invoke handler 8 catAPIHandler(recorder, req) 9 10 // 4. Check the response 11 if recorder.Code != http.StatusOK { 12 t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.Sta 13 } 14 15 // 1. Create test request req, _ := http.NewRequest("GET", "/api/cats", nil) func TestCatAPIHandler(t *testing.T) { 1 2 3 4 // 2. Create recorder (which satisfies http.ResponseWriter) 5 recorder := httptest.NewRecorder() 6 7 // 3. Invoke handler 8 catAPIHandler(recorder, req) 9 10 // 4. Check the response 11 if recorder.Code != http.StatusOK { 12 t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.Sta 13 } 14 } 15 // 2. Create recorder (which satisfies http.ResponseWriter) recorder := httptest.NewRecorder() func TestCatAPIHandler(t *testing.T) { 1 // 1. Create test request 2 req, _ := http.NewRequest("GET", "/api/cats", nil) 3 4 5 6 7 // 3. Invoke handler 8 catAPIHandler(recorder, req) 9 10 // 4. Check the response 11 if recorder.Code != http.StatusOK { 12 t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.Sta 13 } 14 } 15 // 3. Invoke handler catAPIHandler(recorder, req) func TestCatAPIHandler(t *testing.T) { 1 // 1. Create test request 2 req, _ := http.NewRequest("GET", "/api/cats", nil) 3 4 // 2. Create recorder (which satisfies http.ResponseWriter) 5 recorder := httptest.NewRecorder() 6 7 8 9 10 // 4. Check the response 11 if recorder.Code != http.StatusOK { 12 t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.Sta 13 } 14 } 15 // 4. Check the response if recorder.Code != http.StatusOK { t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.Sta } func TestCatAPIHandler(t *testing.T) { 1 // 1. Create test request 2 req, _ := http.NewRequest("GET", "/api/cats", nil) 3 4 // 2. Create recorder (which satisfies http.ResponseWriter) 5 recorder := httptest.NewRecorder() 6 7 // 3. Invoke handler 8 catAPIHandler(recorder, req) 9 10 11 12 13 14 } 15 func TestCatAPIHandler(t *testing.T) { // 1. Create test request req, _ := http.NewRequest("GET", "/api/cats", nil) // 2. Create recorder (which satisfies http.ResponseWriter) recorder := httptest.NewRecorder() // 3. Invoke handler catAPIHandler(recorder, req) // 4. Check the response if recorder.Code != http.StatusOK { t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.Sta } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  • 19. RUN TEST # Run tests go test -v ./... 1 2 === RUN TestCatAPIHandler 3 --- PASS: TestCatAPIHandler (0.00s) 4 PASS 5 coverage: 50.0% of statements 6 ok devopscon.com/cats 0.127s coverage: 50.0% of stateme 7 === RUN TestCatAPIHandler --- PASS: TestCatAPIHandler (0.00s) PASS coverage: 50.0% of statements ok devopscon.com/cats 0.127s coverage: 50.0% of statem # Run tests 1 go test -v ./... 2 3 4 5 6 7
  • 20. BUILD WITH Makefile build: go build -o dist/"${BIN_FILE}" .DEFAULT_GOAL := build 1 BIN_FILE=cats 2 3 4 5 6 test: 7 go test -v ./... 8 9 run: 10 ./"${BIN_FILE}" 11 12 clean: 13 go clean 14 test: go test -v ./... .DEFAULT_GOAL := build 1 BIN_FILE=cats 2 3 build: 4 go build -o dist/"${BIN_FILE}" 5 6 7 8 9 run: 10 ./"${BIN_FILE}" 11 12 clean: 13 go clean 14 run: ./"${BIN_FILE}" .DEFAULT_GOAL := build 1 BIN_FILE=cats 2 3 build: 4 go build -o dist/"${BIN_FILE}" 5 6 test: 7 go test -v ./... 8 9 10 11 12 clean: 13 go clean 14 clean: go clean .DEFAULT_GOAL := build 1 BIN_FILE=cats 2 3 build: 4 go build -o dist/"${BIN_FILE}" 5 6 test: 7 go test -v ./... 8 9 run: 10 ./"${BIN_FILE}" 11 12 13 14 .DEFAULT_GOAL := build BIN_FILE=cats build: go build -o dist/"${BIN_FILE}" test: go test -v ./... run: ./"${BIN_FILE}" clean: go clean 1 2 3 4 5 6 7 8 9 10 11 12 13 14
  • 21. DEMO
  • 23. CATS HANDLER BASIC TEMPLATE SETUP func indexHandler(w http.ResponseWriter, r *http.Request) { var tpl = template.Must(template.ParseFiles("index.html")) tpl.Execute(w, nil) 1 2 3 } 4 5 func main() { 6 http.HandleFunc("/", indexHandler) 7 http.ListenAndServe(":8080", nil) 8 } 9 func indexHandler(w http.ResponseWriter, r *http.Request) { var tpl = template.Must(template.ParseFiles("index.html")) tpl.Execute(w, nil) } func main() { http.HandleFunc("/", indexHandler) http.ListenAndServe(":8080", nil) } 1 2 3 4 5 6 7 8 9 func indexHandler(w http.ResponseWriter, r *http.Request) { var tpl = template.Must(template.ParseFiles("index.html")) tpl.Execute(w, nil) } func main() { http.HandleFunc("/", indexHandler) http.ListenAndServe(":8080", nil) } 1 2 3 4 5 6 7 8 9
  • 24. CATS HANDLER WITH MULTIPLEXER mux := http.NewServeMux() mux.HandleFunc("/", indexHandler) func indexHandler(w http.ResponseWriter, r *http.Request) { 1 var tpl = template.Must(template.ParseFiles("index.html")) 2 tpl.Execute(w, nil) 3 } 4 5 func main() { 6 7 8 9 http.ListenAndServe(":8080", mux) 10 } 11 http.ListenAndServe(":8080", mux) func indexHandler(w http.ResponseWriter, r *http.Request) { 1 var tpl = template.Must(template.ParseFiles("index.html")) 2 tpl.Execute(w, nil) 3 } 4 5 func main() { 6 mux := http.NewServeMux() 7 mux.HandleFunc("/", indexHandler) 8 9 10 } 11 func indexHandler(w http.ResponseWriter, r *http.Request) { var tpl = template.Must(template.ParseFiles("index.html")) tpl.Execute(w, nil) } func main() { mux := http.NewServeMux() mux.HandleFunc("/", indexHandler) http.ListenAndServe(":8080", mux) } 1 2 3 4 5 6 7 8 9 10 11
  • 25. SERVE FILES FROM FILESYSTEM // Serve files fs := http.FileServer(http.Dir("assets")) mux.Handle("/assets/", http.StripPrefix("/assets/", fs)) func main() { 1 mux := http.NewServeMux() 2 mux.HandleFunc("/", indexHandler) 3 4 5 6 7 8 http.ListenAndServe(":8080", mux) 9 } 10
  • 26. SERVE FILES EMBEDDED IN BINARY // Serve files mux.Handle("/assets/", http.FileServer(http.FS(assets))) //go:embed assets 1 var assets embed.FS 2 3 func main() { 4 mux := http.NewServeMux() 5 mux.HandleFunc("/", indexHandler) 6 7 8 9 10 http.ListenAndServe(":8080", mux) 11 } 12 //go:embed assets var assets embed.FS // Serve files mux.Handle("/assets/", http.FileServer(http.FS(assets))) 1 2 3 func main() { 4 mux := http.NewServeMux() 5 mux.HandleFunc("/", indexHandler) 6 7 8 9 10 http.ListenAndServe(":8080", mux) 11 } 12 mux.HandleFunc("/", indexHandler) mux.Handle("/assets/", http.FileServer(http.FS(assets))) //go:embed assets 1 var assets embed.FS 2 3 func main() { 4 mux := http.NewServeMux() 5 6 7 // Serve files 8 9 10 http.ListenAndServe(":8080", mux) 11 } 12
  • 28. CATS HANDLER TEMPLATE WITH DATA main.go type Cat struct { Name string } func indexHandler(w ResponseWriter, r *Request) { // Create cat slice cat := make([]Cat, 1) // Add cat ginger cat[0] = Cat{Name: "Ginger"} // Render template tpl.Execute(w, cat) } index.html <body> <h1>Cats App</h1> {{ range. }} <h2>{{ .Name }}</h2> {{ end }} </body>
  • 30. CATS HANDLER WITH CATS API Query Cats API GET https://api.thecatapi.com/v1/breeds?limit=5 [ { "id": "abys", "name": "Abyssinian", "image": { "url": "https://cdn2.thecatapi.com/images/0XYvRd7oD.jpg } }, { "id": "aege", "name": "Aegean", "image": { "url": "https://cdn2.thecatapi.com/images/ozEvzdVM-.jpg } }, ... ] Map JSON type Cat struct { ID string `json:"id"` Name string `json:"name"` Image struct { URL string `json:"url"` } `json:"image"` }
  • 32. CATS HANDLER WITH CATS API resp, err := http.Get("https://api.thecatapi.com/v1/breeds?limit=5") if err != nil { http.Error(w, "Cats API error", http.StatusInternalServerError) return } func indexHandler(w http.ResponseWriter, r *http.Request) { 1 2 3 4 5 6 7 // Create cat slice 8 cat := make([]Cat, 5) 9 10 // Read and parse body 11 defer resp.Body.Close() 12 body, _ := ioutil.ReadAll(resp.Body) 13 json.Unmarshal(body, &cat) 14 15 tpl.Execute(w, cat) 16 } 17 // Create cat slice cat := make([]Cat, 5) func indexHandler(w http.ResponseWriter, r *http.Request) { 1 resp, err := http.Get("https://api.thecatapi.com/v1/breeds?limit=5") 2 if err != nil { 3 http.Error(w, "Cats API error", http.StatusInternalServerError) 4 return 5 } 6 7 8 9 10 // Read and parse body 11 defer resp.Body.Close() 12 body, _ := ioutil.ReadAll(resp.Body) 13 json.Unmarshal(body, &cat) 14 15 tpl.Execute(w, cat) 16 } 17 // Read and parse body defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) json.Unmarshal(body, &cat) func indexHandler(w http.ResponseWriter, r *http.Request) { 1 resp, err := http.Get("https://api.thecatapi.com/v1/breeds?limit=5") 2 if err != nil { 3 http.Error(w, "Cats API error", http.StatusInternalServerError) 4 return 5 } 6 7 // Create cat slice 8 cat := make([]Cat, 5) 9 10 11 12 13 14 15 tpl.Execute(w, cat) 16 } 17 func indexHandler(w http.ResponseWriter, r *http.Request) { resp, err := http.Get("https://api.thecatapi.com/v1/breeds?limit=5") if err != nil { http.Error(w, "Cats API error", http.StatusInternalServerError) return } // Create cat slice cat := make([]Cat, 5) // Read and parse body defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) json.Unmarshal(body, &cat) tpl.Execute(w, cat) } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
  • 33. MIDDLEWARE cross cutting functionality for all requests (e.g. logging, authentication) # create a chain of handlers router => middleware handler => application handler # satisfy the interface http.Handler #
  • 34. MIDDLEWARE TO LOG REQUESTS http.ListenAndServe(":8080", loggingMiddleware(mux)) func loggingMiddleware(next http.Handler) http.Handler { 1 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Reque 2 log.Printf("%v requested URL %v", r.Host, r.URL) 3 next.ServeHTTP(w, r) 4 }) 5 } 6 7 func main() { 8 mux := http.NewServeMux() 9 mux.HandleFunc("/", indexHandler) 10 11 12 } 13 func loggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Reque log.Printf("%v requested URL %v", r.Host, r.URL) next.ServeHTTP(w, r) }) } 1 2 3 4 5 6 7 func main() { 8 mux := http.NewServeMux() 9 mux.HandleFunc("/", indexHandler) 10 11 http.ListenAndServe(":8080", loggingMiddleware(mux)) 12 } 13 func loggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Reque log.Printf("%v requested URL %v", r.Host, r.URL) next.ServeHTTP(w, r) }) } func main() { mux := http.NewServeMux() mux.HandleFunc("/", indexHandler) http.ListenAndServe(":8080", loggingMiddleware(mux)) 1 2 3 4 5 6 7 8 9 10 11 12 } 13
  • 35. DEMO
  • 36. BASICS   Dev Setup Variables, Slices, Loops Struct Errors # # # # CATS APP API Handler (with JSON) Http Test Build # # # CATS APP WEB Multiplexer (Router) File Server Template Middleware # # # #