Go Crashkurs
Hello Gopher
package main
import "fmt"
func main() {
fmt.Println("Hello Gopher!")
}
Ausführen
go build hellogopher.go // 1. Code kompilieren
./hellogopher // 2. Binary ausführen
go run hellogopher.go // Code kompilieren und ausführen
Entwicklung
JetBrains
GoLand
Visual
Studio Code Vim Go
5 Fakten zu Go
1. statisches Typsystem
2. Garbage Collection
3. keine Vererbung
4. Concurrency eingebaut
5. native Ausführung
Linux, Win, z/OS, 386, amd64, ARM, wasm, ...
Grundlagen
Variablen, Slices, Schleifen
// Variable
var frank string = "Frank"
claire := "Claire"
1
2
3
4
// Array (fixe Länge)
5
namesArray := [3]string{frank, claire, "Zoe"}
6
7
// Slice (variable Länge)
8
namesSlice := make([]string, 2)
9
namesSlice[0] = frank
10
11
// Schleife
12
for i, name := range namesSlice {
13
fmt.Println("Hello " + name + "!")
14
}
15
// Array (fixe Länge)
namesArray := [3]string{frank, claire, "Zoe"}
// Variable
1
var frank string = "Frank"
2
claire := "Claire"
3
4
5
6
7
// Slice (variable Länge)
8
namesSlice := make([]string, 2)
9
namesSlice[0] = frank
10
11
// Schleife
12
for i, name := range namesSlice {
13
fmt.Println("Hello " + name + "!")
14
}
15
// Slice (variable Länge)
namesSlice := make([]string, 2)
namesSlice[0] = frank
// Variable
1
var frank string = "Frank"
2
claire := "Claire"
3
4
// Array (fixe Länge)
5
namesArray := [3]string{frank, claire, "Zoe"}
6
7
8
9
10
11
// Schleife
12
for i, name := range namesSlice {
13
fmt.Println("Hello " + name + "!")
14
}
15
// Schleife
for i, name := range namesSlice {
fmt.Println("Hello " + name + "!")
}
// Variable
1
var frank string = "Frank"
2
claire := "Claire"
3
4
// Array (fixe Länge)
5
namesArray := [3]string{frank, claire, "Zoe"}
6
7
// Slice (variable Länge)
8
namesSlice := make([]string, 2)
9
namesSlice[0] = frank
10
11
12
13
14
15
Struct statt Klasse
type Congressman struct {
Name string
}
1
2
3
4
func main() {
5
c := Congressman{Name: "Peter Russo"}
6
fmt.Println("Hello " + c.Name + "!")
7
}
8
c := Congressman{Name: "Peter Russo"}
fmt.Println("Hello " + c.Name + "!")
type Congressman struct {
1
Name string
2
}
3
4
func main() {
5
6
7
}
8
type Congressman struct {
Name string
}
func main() {
c := Congressman{Name: "Peter Russo"}
fmt.Println("Hello " + c.Name + "!")
}
1
2
3
4
5
6
7
8
Function Receiverstatt Instanzmethode
func (c Congressman) swearOathOfOffice() {
fmt.Printf("I, %v, swear to serve the USA.", c.Name)
}
type Congressman struct {
1
Name string
2
}
3
4
5
6
7
8
func main() {
9
c := Congressman{Name: "Peter Russo"}
10
c.swearOathOfOffice();
11
}
12
func (c Congressman) swearOathOfOffice() {
fmt.Printf("I, %v, swear to serve the USA.", c.Name)
}
c := Congressman{Name: "Peter Russo"}
c.swearOathOfOffice();
type Congressman struct {
1
Name string
2
}
3
4
5
6
7
8
func main() {
9
10
11
}
12
Interface
type Greeter interface {
greet()
}
1
2
3
4
func passBy(c1 Greeter, c2 Greeter) {
5
c1.greet()
6
c2.greet()
7
}
8
9
func main() {
10
c := Congressman{Name: "Frank U."}
11
e := Enemy{}
12
passBy(c, e)
13
}
14
func passBy(c1 Greeter, c2 Greeter) {
c1.greet()
c2.greet()
}
type Greeter interface {
1
greet()
2
}
3
4
5
6
7
8
9
func main() {
10
c := Congressman{Name: "Frank U."}
11
e := Enemy{}
12
passBy(c, e)
13
}
14
func main() {
c := Congressman{Name: "Frank U."}
e := Enemy{}
passBy(c, e)
}
type Greeter interface {
1
greet()
2
}
3
4
func passBy(c1 Greeter, c2 Greeter) {
5
c1.greet()
6
c2.greet()
7
}
8
9
10
11
12
13
14
type Greeter interface {
greet()
}
1
2
3
4
func passBy(c1 Greeter, c2 Greeter) {
5
c1.greet()
6
c2.greet()
7
}
8
9
func main() {
10
c := Congressman{Name: "Frank U."}
11
e := Enemy{}
12
passBy(c, e)
13
}
14
type Congressman struct {
Name string
}
func (c Congressman) greet() {
fmt.Println("Hello", c.Name)
}
type Enemy struct{}
func (e Enemy) greet() {
fmt.Println("Go to hell!")
}
Struct Embedding statt Vererbung
type Congressman struct {
Name string
}
1
2
3
4
type President struct {
5
Congressman // Embedded
6
7
NuclearWeaponCode string
8
}
9
10
func main() {
11
p := President{NuclearWeaponCode: "123"}
12
p.Name = "Frank Underwood"
13
p.swearOathOfOffice();
14
}
15
type President struct {
Congressman // Embedded
NuclearWeaponCode string
}
type Congressman struct {
1
Name string
2
}
3
4
5
6
7
8
9
10
func main() {
11
p := President{NuclearWeaponCode: "123"}
12
p.Name = "Frank Underwood"
13
p.swearOathOfOffice();
14
}
15
type President struct {
Congressman // Embedded
NuclearWeaponCode string
}
p := President{NuclearWeaponCode: "123"}
p.Name = "Frank Underwood"
p.swearOathOfOffice();
type Congressman struct {
1
Name string
2
}
3
4
5
6
7
8
9
10
func main() {
11
12
13
14
}
15
Fehler
// Fehler als Rückgabewert
func (c Congressman) bribe(amount float64) error {
if c.Name != "Peter Russo" {
return fmt.Errorf("Not corrupt!")
}
c.AccountBalance += amount
return nil
}
1
2
3
4
5
6
7
8
9
func main() {
10
c := Congressman{Name: "Jackie Sharp", AccountBalance: -10.0}
11
12
// Fehler behandeln
13
err := c.bribe(5000.0)
14
if err != nil {
15
fmt.Printf("%v is not bribeable (%v).n", c.Name, err)
16
}
17
}
18
// Fehler behandeln
err := c.bribe(5000.0)
if err != nil {
fmt.Printf("%v is not bribeable (%v).n", c.Name, err)
}
// Fehler als Rückgabewert
1
func (c Congressman) bribe(amount float64) error {
2
if c.Name != "Peter Russo" {
3
return fmt.Errorf("Not corrupt!")
4
}
5
c.AccountBalance += amount
6
return nil
7
}
8
9
func main() {
10
c := Congressman{Name: "Jackie Sharp", AccountBalance: -10.0}
11
12
13
14
15
16
17
}
18
Generics
// Generische Funktion: Hunde-Alter * 3 = Menschen-Alter
func humanAge[T int32 | float64](dogAge T) T {
return dogAge * 7
}
1
2
3
4
5
func main() {
6
// Generische Funktion mit int32 aufrufen
7
var i int32 = humanAge[int32](3)
8
fmt.Println("int:", i)
9
10
// Generische Funktion mit float64 aufrufen
11
var f float64 = humanAge[float64](4.9)
12
fmt.Println("float:", f)
13
}
14
// Generische Funktion: Hunde-Alter * 3 = Menschen-Alter
func humanAge[T int32 | float64](dogAge T) T {
return dogAge * 7
}
// Generische Funktion mit int32 aufrufen
var i int32 = humanAge[int32](3)
1
2
3
4
5
func main() {
6
7
8
fmt.Println("int:", i)
9
10
// Generische Funktion mit float64 aufrufen
11
var f float64 = humanAge[float64](4.9)
12
fmt.Println("float:", f)
13
}
14
// Generische Funktion: Hunde-Alter * 3 = Menschen-Alter
func humanAge[T int32 | float64](dogAge T) T {
return dogAge * 7
}
// Generische Funktion mit float64 aufrufen
var f float64 = humanAge[float64](4.9)
1
2
3
4
5
func main() {
6
// Generische Funktion mit int32 aufrufen
7
var i int32 = humanAge[int32](3)
8
fmt.Println("int:", i)
9
10
11
12
fmt.Println("float:", f)
13
}
14
// Generische Funktion: Hunde-Alter * 3 = Menschen-Alter
func humanAge[T int32 | float64](dogAge T) T {
return dogAge * 7
}
func main() {
// Generische Funktion mit int32 aufrufen
var i int32 = humanAge[int32](3)
fmt.Println("int:", i)
// Generische Funktion mit float64 aufrufen
var f float64 = humanAge[float64](4.9)
fmt.Println("float:", f)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Nebenläufig
Programmieren 🚀
Concurrency
Goroutine
leichtgewichtigerThread
Channel
Kanal fürNachrichten, dient der
Kommunkation
Synchronisation
von Goroutinen
Goroutine
func main() {
go HelloCongressman("Russo")
}
func HelloCongressman(name string) {
1
fmt.Println("Hello Congressman", name)
2
}
3
4
5
6
7
Channel
// Deklarieren und Initialisieren
c := make(chan int)
1
2
3
// Nachricht über Channel senden
4
c <- 1
5
6
// Nachricht von Channel empfangen,
7
// "Pfeil" gibt Richtung des Datenfluss an
8
value = <-c
9
// Nachricht über Channel senden
c <- 1
// Deklarieren und Initialisieren
1
c := make(chan int)
2
3
4
5
6
// Nachricht von Channel empfangen,
7
// "Pfeil" gibt Richtung des Datenfluss an
8
value = <-c
9
// Nachricht von Channel empfangen,
// "Pfeil" gibt Richtung des Datenfluss an
value = <-c
// Deklarieren und Initialisieren
1
c := make(chan int)
2
3
// Nachricht über Channel senden
4
c <- 1
5
6
7
8
9
Debatte mit Goroutinen und Channels
debate := make(chan int) // Channel deklarieren und initialisieren
func speaker(name string, debate chan int) {
1
for {
2
microphone := <-debate // Auf Mikro warten (Channel receive)
3
4
fmt.Printf("Turn %v: %v says '%v'n", microphone, name, randomAnswer())
5
time.Sleep(400 * time.Millisecond)
6
7
microphone++
8
debate <- microphone // Mikro zurückgeben (Channel send)
9
}
10
}
11
12
func main() {
13
14
15
go speaker("Jackie", debate)
16
go speaker("Frank", debate)
17
18
microphone := 1
19
debate <- microphone // Mikro geben und Diskussion starten
20
time.Sleep(2 * time.Second) // Dauer der Diskussion
21
<-debate // Mikro nehmen und Diskussion beenden
22
}
23
debate := make(chan int) // Channel deklarieren und initialisieren
go speaker("Jackie", debate)
go speaker("Frank", debate)
func speaker(name string, debate chan int) {
1
for {
2
microphone := <-debate // Auf Mikro warten (Channel receive)
3
4
fmt.Printf("Turn %v: %v says '%v'n", microphone, name, randomAnswer())
5
time.Sleep(400 * time.Millisecond)
6
7
microphone++
8
debate <- microphone // Mikro zurückgeben (Channel send)
9
}
10
}
11
12
func main() {
13
14
15
16
17
18
microphone := 1
19
debate <- microphone // Mikro geben und Diskussion starten
20
time.Sleep(2 * time.Second) // Dauer der Diskussion
21
<-debate // Mikro nehmen und Diskussion beenden
22
}
23
debate := make(chan int) // Channel deklarieren und initialisieren
go speaker("Jackie", debate)
go speaker("Frank", debate)
microphone := 1
debate <- microphone // Mikro geben und Diskussion starten
time.Sleep(2 * time.Second) // Dauer der Diskussion
<-debate // Mikro nehmen und Diskussion beenden
func speaker(name string, debate chan int) {
1
for {
2
microphone := <-debate // Auf Mikro warten (Channel receive)
3
4
fmt.Printf("Turn %v: %v says '%v'n", microphone, name, randomAnswer())
5
time.Sleep(400 * time.Millisecond)
6
7
microphone++
8
debate <- microphone // Mikro zurückgeben (Channel send)
9
}
10
}
11
12
func main() {
13
14
15
16
17
18
19
20
21
22
}
23
func speaker(name string, debate chan int) {
for {
microphone := <-debate // Auf Mikro warten (Channel receive)
fmt.Printf("Turn %v: %v says '%v'n", microphone, name, randomAnswer())
time.Sleep(400 * time.Millisecond)
microphone++
debate <- microphone // Mikro zurückgeben (Channel send)
}
}
debate := make(chan int) // Channel deklarieren und initialisieren
go speaker("Jackie", debate)
go speaker("Frank", debate)
microphone := 1
debate <- microphone // Mikro geben und Diskussion starten
time.Sleep(2 * time.Second) // Dauer der Diskussion
<-debate // Mikro nehmen und Diskussion beenden
1
2
3
4
5
6
7
8
9
10
11
12
func main() {
13
14
15
16
17
18
19
20
21
22
}
23
Debatte mit Goroutinen und Channels
>_ go run debate.go
Turn 1: Frank says 'You liar.'
Turn 2: Jackie says 'Back off.'
Turn 3: Frank says 'Back off.'
Turn 4: Jackie says 'My point.'
Turn 5: Frank says 'You liar.'
Turn 6: Jackie says 'You're wrong.'
Web App
TarifrechnerDogOP
TarifrechnerDogOp
REST API die Hunde OPVersicherung berechnet
#
Bereitstellung als Container
#
Konfiguration überUmgebungsvariablen
#
Projekt DogOPaufsetzen
go mod init crossnative/dogop // Go Modul initialisieren
Projektstruktur
go.mod // Modul Deskriptor mit Dependencies
go.sum // Checksummen der Dependencies
Projekt DogOPaufsetzen
import (
"net/http"
)
func main() {
// 1. HTTP Router erstellen
r := http.NewServeMux()
package main
1
2
3
4
5
6
7
8
9
10
// 2. HTTP Handler registieren
11
r.HandleFunc("GET /", func(w http.ResponseWriter, req *http.Request) {
12
w.Write([]byte("Hello DogOp!"))
13
})
14
15
// 3. HTTP-Server starten
16
http.ListenAndServe(":8080", r)
17
}
18
// 2. HTTP Handler registieren
r.HandleFunc("GET /", func(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("Hello DogOp!"))
})
package main
1
2
import (
3
"net/http"
4
)
5
6
func main() {
7
// 1. HTTP Router erstellen
8
r := http.NewServeMux()
9
10
11
12
13
14
15
// 3. HTTP-Server starten
16
http.ListenAndServe(":8080", r)
17
}
18
// 3. HTTP-Server starten
http.ListenAndServe(":8080", r)
package main
1
2
import (
3
"net/http"
4
)
5
6
func main() {
7
// 1. HTTP Router erstellen
8
r := http.NewServeMux()
9
10
// 2. HTTP Handler registieren
11
r.HandleFunc("GET /", func(w http.ResponseWriter, req *http.Request) {
12
w.Write([]byte("Hello DogOp!"))
13
})
14
15
16
17
}
18
package main
import (
"net/http"
)
func main() {
// 1. HTTP Router erstellen
r := http.NewServeMux()
// 2. HTTP Handler registieren
r.HandleFunc("GET /", func(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("Hello DogOp!"))
})
// 3. HTTP-Server starten
http.ListenAndServe(":8080", r)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Bauen und Ausführen
// 1. Kompilieren in Binary
go build -o build/dogop .
// 2. Binary ausführen
./build/dogop
Bauen und Ausführen
REST API fürRechner
Request
POST /api/quote
content-type: application/json
{
"age": 8,
"breed": "chow"
}
Response
HTTP/1.1 200 OK
Content-Type: application/json
{
"age": 8,
"breed": "chow",
"tariffs": [
{
"name": "Dog OP _ Basic",
"rate": 12.4
}
]
}
REST API fürRechner
func main() {
r.HandleFunc("POST /api/quote", HandleQuote)
}
func HandleQuote(w http.ResponseWriter, r *http.Request) {
1
// 1. JSON Request lesen
2
var q Quote
3
json.NewDecoder(r.Body).Decode(&q)
4
5
// 2. Tarif berechnen
6
tariff := Tariff{Name: "Dog OP _ Basic", Rate: 12.4}
7
quote.Tariffs = []Tariff{tariff}
8
9
// 3. JSON Response schreiben
10
json.NewEncoder(w).Encode(quote)
11
}
12
13
14
r := http.NewServeMux()
15
16
17
18
r.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
19
w.Write([]byte("Hello DogOp!"))
20
})
21
22
http.ListenAndServe(":8080", r)
23
24
func HandleQuote(w http.ResponseWriter, r *http.Request) {
}
1
// 1. JSON Request lesen
2
var q Quote
3
json.NewDecoder(r.Body).Decode(&q)
4
5
// 2. Tarif berechnen
6
tariff := Tariff{Name: "Dog OP _ Basic", Rate: 12.4}
7
quote.Tariffs = []Tariff{tariff}
8
9
// 3. JSON Response schreiben
10
json.NewEncoder(w).Encode(quote)
11
12
13
func main() {
14
r := http.NewServeMux()
15
16
r.HandleFunc("POST /api/quote", HandleQuote)
17
18
r.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
19
w.Write([]byte("Hello DogOp!"))
20
})
21
22
http.ListenAndServe(":8080", r)
23
}
24
// 1. JSON Request lesen
var q Quote
json.NewDecoder(r.Body).Decode(&q)
func HandleQuote(w http.ResponseWriter, r *http.Request) {
1
2
3
4
5
// 2. Tarif berechnen
6
tariff := Tariff{Name: "Dog OP _ Basic", Rate: 12.4}
7
quote.Tariffs = []Tariff{tariff}
8
9
// 3. JSON Response schreiben
10
json.NewEncoder(w).Encode(quote)
11
}
12
13
func main() {
14
r := http.NewServeMux()
15
16
r.HandleFunc("POST /api/quote", HandleQuote)
17
18
r.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
19
w.Write([]byte("Hello DogOp!"))
20
})
21
22
http.ListenAndServe(":8080", r)
23
}
24
// 2. Tarif berechnen
tariff := Tariff{Name: "Dog OP _ Basic", Rate: 12.4}
quote.Tariffs = []Tariff{tariff}
func HandleQuote(w http.ResponseWriter, r *http.Request) {
1
// 1. JSON Request lesen
2
var q Quote
3
json.NewDecoder(r.Body).Decode(&q)
4
5
6
7
8
9
// 3. JSON Response schreiben
10
json.NewEncoder(w).Encode(quote)
11
}
12
13
func main() {
14
r := http.NewServeMux()
15
16
r.HandleFunc("POST /api/quote", HandleQuote)
17
18
r.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
19
w.Write([]byte("Hello DogOp!"))
20
})
21
22
http.ListenAndServe(":8080", r)
23
}
24
// 3. JSON Response schreiben
json.NewEncoder(w).Encode(quote)
func HandleQuote(w http.ResponseWriter, r *http.Request) {
1
// 1. JSON Request lesen
2
var q Quote
3
json.NewDecoder(r.Body).Decode(&q)
4
5
// 2. Tarif berechnen
6
tariff := Tariff{Name: "Dog OP _ Basic", Rate: 12.4}
7
quote.Tariffs = []Tariff{tariff}
8
9
10
11
}
12
13
func main() {
14
r := http.NewServeMux()
15
16
r.HandleFunc("POST /api/quote", HandleQuote)
17
18
r.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
19
w.Write([]byte("Hello DogOp!"))
20
})
21
22
http.ListenAndServe(":8080", r)
23
}
24
func HandleQuote(w http.ResponseWriter, r *http.Request) {
// 1. JSON Request lesen
var q Quote
json.NewDecoder(r.Body).Decode(&q)
// 2. Tarif berechnen
tariff := Tariff{Name: "Dog OP _ Basic", Rate: 12.4}
quote.Tariffs = []Tariff{tariff}
// 3. JSON Response schreiben
json.NewEncoder(w).Encode(quote)
}
func main() {
r := http.NewServeMux()
r.HandleFunc("POST /api/quote", HandleQuote)
r.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello DogOp!"))
})
http.ListenAndServe(":8080", r)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Achtung, noch ohne Fehlerhandling! 💣
Struct fürJSON
type Tariff struct {
Name string `json:"name"`
Rate float64 `json:"rate"`
}
1
2
3
4
5
type Quote struct {
6
Age int `json:"age"`
7
Breed string `json:"breed"`
8
Tariffs []Tariff `json:"tariffs"`
9
}
10
type Quote struct {
Age int `json:"age"`
Breed string `json:"breed"`
Tariffs []Tariff `json:"tariffs"`
}
type Tariff struct {
1
Name string `json:"name"`
2
Rate float64 `json:"rate"`
3
}
4
5
6
7
8
9
10
type Tariff struct {
Name string `json:"name"`
Rate float64 `json:"rate"`
}
type Quote struct {
Age int `json:"age"`
Breed string `json:"breed"`
Tariffs []Tariff `json:"tariffs"`
}
1
2
3
4
5
6
7
8
9
10
// Struct erzeugen
tariff := Tariff{Name: "Dog OP _ Basic", Rate: 12.4}
Fehler💣
func HandleQuote(w http.ResponseWriter, r *http.Request) {
}
1
// 1. JSON Request lesen
2
var q Quote
3
json.NewDecoder(r.Body).Decode(&q) // 💣 Fehler möglich!
4
5
// 2. Tarif berechnen
6
tariff := Tariff{Name: "Dog OP _ Basic", Rate: 12.4}
7
quote.Tariffs = []Tariff{tariff}
8
9
// 3. JSON Response schreiben
10
json.NewEncoder(w).Encode(quote) // 💣 Fehler möglich!
11
12
json.NewDecoder(r.Body).Decode(&q) // 💣 Fehler möglich!
json.NewEncoder(w).Encode(quote) // 💣 Fehler möglich!
func HandleQuote(w http.ResponseWriter, r *http.Request) {
1
// 1. JSON Request lesen
2
var q Quote
3
4
5
// 2. Tarif berechnen
6
tariff := Tariff{Name: "Dog OP _ Basic", Rate: 12.4}
7
quote.Tariffs = []Tariff{tariff}
8
9
// 3. JSON Response schreiben
10
11
}
12
Fehler💣
func HandleQuote(w http.ResponseWriter, r *http.Request) {
}
1
// 1. JSON Request lesen
2
var q Quote
3
4
// Potentieller Fehler
5
err := json.NewDecoder(r.Body).Decode(&q)
6
7
// Auf Fehler prüfen
8
if err != nil {
9
// Fehler behandeln
10
http.Error(w, "Could not decode quote.😔", http.StatusBadRequest)
11
return
12
}
13
14
// ...
15
16
// Potentieller Fehler
err := json.NewDecoder(r.Body).Decode(&q)
func HandleQuote(w http.ResponseWriter, r *http.Request) {
1
// 1. JSON Request lesen
2
var q Quote
3
4
5
6
7
// Auf Fehler prüfen
8
if err != nil {
9
// Fehler behandeln
10
http.Error(w, "Could not decode quote.😔", http.StatusBadRequest)
11
return
12
}
13
14
// ...
15
}
16
// Auf Fehler prüfen
if err != nil {
}
func HandleQuote(w http.ResponseWriter, r *http.Request) {
1
// 1. JSON Request lesen
2
var q Quote
3
4
// Potentieller Fehler
5
err := json.NewDecoder(r.Body).Decode(&q)
6
7
8
9
// Fehler behandeln
10
http.Error(w, "Could not decode quote.😔", http.StatusBadRequest)
11
return
12
13
14
// ...
15
}
16
func HandleQuote(w http.ResponseWriter, r *http.Request) {
// 1. JSON Request lesen
var q Quote
// Potentieller Fehler
err := json.NewDecoder(r.Body).Decode(&q)
// Auf Fehler prüfen
if err != nil {
// Fehler behandeln
http.Error(w, "Could not decode quote.😔", http.StatusBadRequest)
return
}
// ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
HTTPHandlertesten
Unit Tests in Standardlib enthalten
#
Tests in Datei main_test.go
#
HTTPHandlertesten
func TestHandleQuote(t *testing.T) {
}
1
// 1. HTTP Recorder erstellen
2
recorder := httptest.NewRecorder()
3
4
// 2. Request erstellen (mit Body)
5
body := `
6
{
7
"age": 8,
8
"breed": "chow"
9
}
10
`
11
req, _ := http.NewRequest("GET", "/api/quote", strings.NewReader(body))
12
13
// 3. Handler Funktion aufrufen
14
HandleQuote(recorder, req)
15
16
// 4. Return Code prüfen
17
if recorder.Code != http.StatusOK {
18
t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.StatusOK)
19
}
20
21
// 1. HTTP Recorder erstellen
recorder := httptest.NewRecorder()
func TestHandleQuote(t *testing.T) {
1
2
3
4
// 2. Request erstellen (mit Body)
5
body := `
6
{
7
"age": 8,
8
"breed": "chow"
9
}
10
`
11
req, _ := http.NewRequest("GET", "/api/quote", strings.NewReader(body))
12
13
// 3. Handler Funktion aufrufen
14
HandleQuote(recorder, req)
15
16
// 4. Return Code prüfen
17
if recorder.Code != http.StatusOK {
18
t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.StatusOK)
19
}
20
}
21
// 2. Request erstellen (mit Body)
body := `
{
"age": 8,
"breed": "chow"
}
`
req, _ := http.NewRequest("GET", "/api/quote", strings.NewReader(body))
func TestHandleQuote(t *testing.T) {
1
// 1. HTTP Recorder erstellen
2
recorder := httptest.NewRecorder()
3
4
5
6
7
8
9
10
11
12
13
// 3. Handler Funktion aufrufen
14
HandleQuote(recorder, req)
15
16
// 4. Return Code prüfen
17
if recorder.Code != http.StatusOK {
18
t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.StatusOK)
19
}
20
}
21
// 3. Handler Funktion aufrufen
HandleQuote(recorder, req)
func TestHandleQuote(t *testing.T) {
1
// 1. HTTP Recorder erstellen
2
recorder := httptest.NewRecorder()
3
4
// 2. Request erstellen (mit Body)
5
body := `
6
{
7
"age": 8,
8
"breed": "chow"
9
}
10
`
11
req, _ := http.NewRequest("GET", "/api/quote", strings.NewReader(body))
12
13
14
15
16
// 4. Return Code prüfen
17
if recorder.Code != http.StatusOK {
18
t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.StatusOK)
19
}
20
}
21
// 4. Return Code prüfen
if recorder.Code != http.StatusOK {
t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.StatusOK)
}
func TestHandleQuote(t *testing.T) {
1
// 1. HTTP Recorder erstellen
2
recorder := httptest.NewRecorder()
3
4
// 2. Request erstellen (mit Body)
5
body := `
6
{
7
"age": 8,
8
"breed": "chow"
9
}
10
`
11
req, _ := http.NewRequest("GET", "/api/quote", strings.NewReader(body))
12
13
// 3. Handler Funktion aufrufen
14
HandleQuote(recorder, req)
15
16
17
18
19
20
}
21
func TestHandleQuote(t *testing.T) {
// 1. HTTP Recorder erstellen
recorder := httptest.NewRecorder()
// 2. Request erstellen (mit Body)
body := `
{
"age": 8,
"breed": "chow"
}
`
req, _ := http.NewRequest("GET", "/api/quote", strings.NewReader(body))
// 3. Handler Funktion aufrufen
HandleQuote(recorder, req)
// 4. Return Code prüfen
if recorder.Code != http.StatusOK {
t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.StatusOK)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
HTTPHandlertesten
go test -v ./...
=== RUN TestHandleQuote
--- PASS: TestHandleQuote (0.00s)
PASS
ok crossnative/dogop 0.228s
HTTPHandlertesten
Dockerfile fürDogOP
# 1. DogOp Builder
FROM golang as builder
WORKDIR /app
ADD . /app
RUN CGO_ENABLED=0 go build -ldflags="-w -s" -o build/dogop .
1
2
3
4
5
6
# 2. DogOp Container
7
FROM alpine
8
COPY --from=builder /app/build/dogop /usr/bin/
9
EXPOSE 8080
10
ENTRYPOINT ["/usr/bin/dogop"]
11
# 2. DogOp Container
FROM alpine
COPY --from=builder /app/build/dogop /usr/bin/
EXPOSE 8080
ENTRYPOINT ["/usr/bin/dogop"]
# 1. DogOp Builder
1
FROM golang as builder
2
WORKDIR /app
3
ADD . /app
4
RUN CGO_ENABLED=0 go build -ldflags="-w -s" -o build/dogop .
5
6
7
8
9
10
11
# 1. DogOp Builder
FROM golang as builder
WORKDIR /app
ADD . /app
RUN CGO_ENABLED=0 go build -ldflags="-w -s" -o build/dogop .
# 2. DogOp Container
FROM alpine
COPY --from=builder /app/build/dogop /usr/bin/
EXPOSE 8080
ENTRYPOINT ["/usr/bin/dogop"]
1
2
3
4
5
6
7
8
9
10
11
Demo
Grundlagen
Variablen, Slices,
Schleifen
Struct
Struct Embedding
Fehler
Generics
#
#
#
#
#
Nebenläufig
Programmieren
Goroutinen
Channels
#
#
Web App DogOp
HTTPRouter
JSON Verbeitung
(HTTP-)Tests
DockerContainer
#
#
#
#
Go Liebt
Microservices Serverless Functions
Kommandozeilen-Tools DevOps und Cloud
3 Gründe fürGo
1. Einfach
2. Mächtig
3. Langweilig
Jan Stamer
jan.stamer@crossnative.com
👉Mehrauf LinkedIn Learning
JAX 2025: Go Crashkurs mit praktischen Beispielen

JAX 2025: Go Crashkurs mit praktischen Beispielen

  • 1.
  • 5.
    Hello Gopher package main import"fmt" func main() { fmt.Println("Hello Gopher!") } Ausführen go build hellogopher.go // 1. Code kompilieren ./hellogopher // 2. Binary ausführen go run hellogopher.go // Code kompilieren und ausführen
  • 6.
  • 7.
    5 Fakten zuGo 1. statisches Typsystem 2. Garbage Collection 3. keine Vererbung 4. Concurrency eingebaut 5. native Ausführung Linux, Win, z/OS, 386, amd64, ARM, wasm, ...
  • 8.
  • 9.
    Variablen, Slices, Schleifen //Variable var frank string = "Frank" claire := "Claire" 1 2 3 4 // Array (fixe Länge) 5 namesArray := [3]string{frank, claire, "Zoe"} 6 7 // Slice (variable Länge) 8 namesSlice := make([]string, 2) 9 namesSlice[0] = frank 10 11 // Schleife 12 for i, name := range namesSlice { 13 fmt.Println("Hello " + name + "!") 14 } 15 // Array (fixe Länge) namesArray := [3]string{frank, claire, "Zoe"} // Variable 1 var frank string = "Frank" 2 claire := "Claire" 3 4 5 6 7 // Slice (variable Länge) 8 namesSlice := make([]string, 2) 9 namesSlice[0] = frank 10 11 // Schleife 12 for i, name := range namesSlice { 13 fmt.Println("Hello " + name + "!") 14 } 15 // Slice (variable Länge) namesSlice := make([]string, 2) namesSlice[0] = frank // Variable 1 var frank string = "Frank" 2 claire := "Claire" 3 4 // Array (fixe Länge) 5 namesArray := [3]string{frank, claire, "Zoe"} 6 7 8 9 10 11 // Schleife 12 for i, name := range namesSlice { 13 fmt.Println("Hello " + name + "!") 14 } 15 // Schleife for i, name := range namesSlice { fmt.Println("Hello " + name + "!") } // Variable 1 var frank string = "Frank" 2 claire := "Claire" 3 4 // Array (fixe Länge) 5 namesArray := [3]string{frank, claire, "Zoe"} 6 7 // Slice (variable Länge) 8 namesSlice := make([]string, 2) 9 namesSlice[0] = frank 10 11 12 13 14 15
  • 10.
    Struct statt Klasse typeCongressman struct { Name string } 1 2 3 4 func main() { 5 c := Congressman{Name: "Peter Russo"} 6 fmt.Println("Hello " + c.Name + "!") 7 } 8 c := Congressman{Name: "Peter Russo"} fmt.Println("Hello " + c.Name + "!") type Congressman struct { 1 Name string 2 } 3 4 func main() { 5 6 7 } 8 type Congressman struct { Name string } func main() { c := Congressman{Name: "Peter Russo"} fmt.Println("Hello " + c.Name + "!") } 1 2 3 4 5 6 7 8
  • 11.
    Function Receiverstatt Instanzmethode func(c Congressman) swearOathOfOffice() { fmt.Printf("I, %v, swear to serve the USA.", c.Name) } type Congressman struct { 1 Name string 2 } 3 4 5 6 7 8 func main() { 9 c := Congressman{Name: "Peter Russo"} 10 c.swearOathOfOffice(); 11 } 12 func (c Congressman) swearOathOfOffice() { fmt.Printf("I, %v, swear to serve the USA.", c.Name) } c := Congressman{Name: "Peter Russo"} c.swearOathOfOffice(); type Congressman struct { 1 Name string 2 } 3 4 5 6 7 8 func main() { 9 10 11 } 12
  • 12.
    Interface type Greeter interface{ greet() } 1 2 3 4 func passBy(c1 Greeter, c2 Greeter) { 5 c1.greet() 6 c2.greet() 7 } 8 9 func main() { 10 c := Congressman{Name: "Frank U."} 11 e := Enemy{} 12 passBy(c, e) 13 } 14 func passBy(c1 Greeter, c2 Greeter) { c1.greet() c2.greet() } type Greeter interface { 1 greet() 2 } 3 4 5 6 7 8 9 func main() { 10 c := Congressman{Name: "Frank U."} 11 e := Enemy{} 12 passBy(c, e) 13 } 14 func main() { c := Congressman{Name: "Frank U."} e := Enemy{} passBy(c, e) } type Greeter interface { 1 greet() 2 } 3 4 func passBy(c1 Greeter, c2 Greeter) { 5 c1.greet() 6 c2.greet() 7 } 8 9 10 11 12 13 14 type Greeter interface { greet() } 1 2 3 4 func passBy(c1 Greeter, c2 Greeter) { 5 c1.greet() 6 c2.greet() 7 } 8 9 func main() { 10 c := Congressman{Name: "Frank U."} 11 e := Enemy{} 12 passBy(c, e) 13 } 14 type Congressman struct { Name string } func (c Congressman) greet() { fmt.Println("Hello", c.Name) } type Enemy struct{} func (e Enemy) greet() { fmt.Println("Go to hell!") }
  • 13.
    Struct Embedding stattVererbung type Congressman struct { Name string } 1 2 3 4 type President struct { 5 Congressman // Embedded 6 7 NuclearWeaponCode string 8 } 9 10 func main() { 11 p := President{NuclearWeaponCode: "123"} 12 p.Name = "Frank Underwood" 13 p.swearOathOfOffice(); 14 } 15 type President struct { Congressman // Embedded NuclearWeaponCode string } type Congressman struct { 1 Name string 2 } 3 4 5 6 7 8 9 10 func main() { 11 p := President{NuclearWeaponCode: "123"} 12 p.Name = "Frank Underwood" 13 p.swearOathOfOffice(); 14 } 15 type President struct { Congressman // Embedded NuclearWeaponCode string } p := President{NuclearWeaponCode: "123"} p.Name = "Frank Underwood" p.swearOathOfOffice(); type Congressman struct { 1 Name string 2 } 3 4 5 6 7 8 9 10 func main() { 11 12 13 14 } 15
  • 14.
    Fehler // Fehler alsRückgabewert func (c Congressman) bribe(amount float64) error { if c.Name != "Peter Russo" { return fmt.Errorf("Not corrupt!") } c.AccountBalance += amount return nil } 1 2 3 4 5 6 7 8 9 func main() { 10 c := Congressman{Name: "Jackie Sharp", AccountBalance: -10.0} 11 12 // Fehler behandeln 13 err := c.bribe(5000.0) 14 if err != nil { 15 fmt.Printf("%v is not bribeable (%v).n", c.Name, err) 16 } 17 } 18 // Fehler behandeln err := c.bribe(5000.0) if err != nil { fmt.Printf("%v is not bribeable (%v).n", c.Name, err) } // Fehler als Rückgabewert 1 func (c Congressman) bribe(amount float64) error { 2 if c.Name != "Peter Russo" { 3 return fmt.Errorf("Not corrupt!") 4 } 5 c.AccountBalance += amount 6 return nil 7 } 8 9 func main() { 10 c := Congressman{Name: "Jackie Sharp", AccountBalance: -10.0} 11 12 13 14 15 16 17 } 18
  • 15.
    Generics // Generische Funktion:Hunde-Alter * 3 = Menschen-Alter func humanAge[T int32 | float64](dogAge T) T { return dogAge * 7 } 1 2 3 4 5 func main() { 6 // Generische Funktion mit int32 aufrufen 7 var i int32 = humanAge[int32](3) 8 fmt.Println("int:", i) 9 10 // Generische Funktion mit float64 aufrufen 11 var f float64 = humanAge[float64](4.9) 12 fmt.Println("float:", f) 13 } 14 // Generische Funktion: Hunde-Alter * 3 = Menschen-Alter func humanAge[T int32 | float64](dogAge T) T { return dogAge * 7 } // Generische Funktion mit int32 aufrufen var i int32 = humanAge[int32](3) 1 2 3 4 5 func main() { 6 7 8 fmt.Println("int:", i) 9 10 // Generische Funktion mit float64 aufrufen 11 var f float64 = humanAge[float64](4.9) 12 fmt.Println("float:", f) 13 } 14 // Generische Funktion: Hunde-Alter * 3 = Menschen-Alter func humanAge[T int32 | float64](dogAge T) T { return dogAge * 7 } // Generische Funktion mit float64 aufrufen var f float64 = humanAge[float64](4.9) 1 2 3 4 5 func main() { 6 // Generische Funktion mit int32 aufrufen 7 var i int32 = humanAge[int32](3) 8 fmt.Println("int:", i) 9 10 11 12 fmt.Println("float:", f) 13 } 14 // Generische Funktion: Hunde-Alter * 3 = Menschen-Alter func humanAge[T int32 | float64](dogAge T) T { return dogAge * 7 } func main() { // Generische Funktion mit int32 aufrufen var i int32 = humanAge[int32](3) fmt.Println("int:", i) // Generische Funktion mit float64 aufrufen var f float64 = humanAge[float64](4.9) fmt.Println("float:", f) } 1 2 3 4 5 6 7 8 9 10 11 12 13 14
  • 16.
  • 17.
  • 18.
    Goroutine func main() { goHelloCongressman("Russo") } func HelloCongressman(name string) { 1 fmt.Println("Hello Congressman", name) 2 } 3 4 5 6 7
  • 19.
    Channel // Deklarieren undInitialisieren c := make(chan int) 1 2 3 // Nachricht über Channel senden 4 c <- 1 5 6 // Nachricht von Channel empfangen, 7 // "Pfeil" gibt Richtung des Datenfluss an 8 value = <-c 9 // Nachricht über Channel senden c <- 1 // Deklarieren und Initialisieren 1 c := make(chan int) 2 3 4 5 6 // Nachricht von Channel empfangen, 7 // "Pfeil" gibt Richtung des Datenfluss an 8 value = <-c 9 // Nachricht von Channel empfangen, // "Pfeil" gibt Richtung des Datenfluss an value = <-c // Deklarieren und Initialisieren 1 c := make(chan int) 2 3 // Nachricht über Channel senden 4 c <- 1 5 6 7 8 9
  • 20.
    Debatte mit Goroutinenund Channels debate := make(chan int) // Channel deklarieren und initialisieren func speaker(name string, debate chan int) { 1 for { 2 microphone := <-debate // Auf Mikro warten (Channel receive) 3 4 fmt.Printf("Turn %v: %v says '%v'n", microphone, name, randomAnswer()) 5 time.Sleep(400 * time.Millisecond) 6 7 microphone++ 8 debate <- microphone // Mikro zurückgeben (Channel send) 9 } 10 } 11 12 func main() { 13 14 15 go speaker("Jackie", debate) 16 go speaker("Frank", debate) 17 18 microphone := 1 19 debate <- microphone // Mikro geben und Diskussion starten 20 time.Sleep(2 * time.Second) // Dauer der Diskussion 21 <-debate // Mikro nehmen und Diskussion beenden 22 } 23 debate := make(chan int) // Channel deklarieren und initialisieren go speaker("Jackie", debate) go speaker("Frank", debate) func speaker(name string, debate chan int) { 1 for { 2 microphone := <-debate // Auf Mikro warten (Channel receive) 3 4 fmt.Printf("Turn %v: %v says '%v'n", microphone, name, randomAnswer()) 5 time.Sleep(400 * time.Millisecond) 6 7 microphone++ 8 debate <- microphone // Mikro zurückgeben (Channel send) 9 } 10 } 11 12 func main() { 13 14 15 16 17 18 microphone := 1 19 debate <- microphone // Mikro geben und Diskussion starten 20 time.Sleep(2 * time.Second) // Dauer der Diskussion 21 <-debate // Mikro nehmen und Diskussion beenden 22 } 23 debate := make(chan int) // Channel deklarieren und initialisieren go speaker("Jackie", debate) go speaker("Frank", debate) microphone := 1 debate <- microphone // Mikro geben und Diskussion starten time.Sleep(2 * time.Second) // Dauer der Diskussion <-debate // Mikro nehmen und Diskussion beenden func speaker(name string, debate chan int) { 1 for { 2 microphone := <-debate // Auf Mikro warten (Channel receive) 3 4 fmt.Printf("Turn %v: %v says '%v'n", microphone, name, randomAnswer()) 5 time.Sleep(400 * time.Millisecond) 6 7 microphone++ 8 debate <- microphone // Mikro zurückgeben (Channel send) 9 } 10 } 11 12 func main() { 13 14 15 16 17 18 19 20 21 22 } 23 func speaker(name string, debate chan int) { for { microphone := <-debate // Auf Mikro warten (Channel receive) fmt.Printf("Turn %v: %v says '%v'n", microphone, name, randomAnswer()) time.Sleep(400 * time.Millisecond) microphone++ debate <- microphone // Mikro zurückgeben (Channel send) } } debate := make(chan int) // Channel deklarieren und initialisieren go speaker("Jackie", debate) go speaker("Frank", debate) microphone := 1 debate <- microphone // Mikro geben und Diskussion starten time.Sleep(2 * time.Second) // Dauer der Diskussion <-debate // Mikro nehmen und Diskussion beenden 1 2 3 4 5 6 7 8 9 10 11 12 func main() { 13 14 15 16 17 18 19 20 21 22 } 23
  • 21.
    Debatte mit Goroutinenund Channels >_ go run debate.go Turn 1: Frank says 'You liar.' Turn 2: Jackie says 'Back off.' Turn 3: Frank says 'Back off.' Turn 4: Jackie says 'My point.' Turn 5: Frank says 'You liar.' Turn 6: Jackie says 'You're wrong.'
  • 22.
  • 23.
    TarifrechnerDogOp REST API dieHunde OPVersicherung berechnet # Bereitstellung als Container # Konfiguration überUmgebungsvariablen #
  • 24.
    Projekt DogOPaufsetzen go modinit crossnative/dogop // Go Modul initialisieren Projektstruktur go.mod // Modul Deskriptor mit Dependencies go.sum // Checksummen der Dependencies
  • 25.
    Projekt DogOPaufsetzen import ( "net/http" ) funcmain() { // 1. HTTP Router erstellen r := http.NewServeMux() package main 1 2 3 4 5 6 7 8 9 10 // 2. HTTP Handler registieren 11 r.HandleFunc("GET /", func(w http.ResponseWriter, req *http.Request) { 12 w.Write([]byte("Hello DogOp!")) 13 }) 14 15 // 3. HTTP-Server starten 16 http.ListenAndServe(":8080", r) 17 } 18 // 2. HTTP Handler registieren r.HandleFunc("GET /", func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("Hello DogOp!")) }) package main 1 2 import ( 3 "net/http" 4 ) 5 6 func main() { 7 // 1. HTTP Router erstellen 8 r := http.NewServeMux() 9 10 11 12 13 14 15 // 3. HTTP-Server starten 16 http.ListenAndServe(":8080", r) 17 } 18 // 3. HTTP-Server starten http.ListenAndServe(":8080", r) package main 1 2 import ( 3 "net/http" 4 ) 5 6 func main() { 7 // 1. HTTP Router erstellen 8 r := http.NewServeMux() 9 10 // 2. HTTP Handler registieren 11 r.HandleFunc("GET /", func(w http.ResponseWriter, req *http.Request) { 12 w.Write([]byte("Hello DogOp!")) 13 }) 14 15 16 17 } 18 package main import ( "net/http" ) func main() { // 1. HTTP Router erstellen r := http.NewServeMux() // 2. HTTP Handler registieren r.HandleFunc("GET /", func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("Hello DogOp!")) }) // 3. HTTP-Server starten http.ListenAndServe(":8080", r) } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
  • 26.
    Bauen und Ausführen //1. Kompilieren in Binary go build -o build/dogop . // 2. Binary ausführen ./build/dogop
  • 27.
  • 28.
    REST API fürRechner Request POST/api/quote content-type: application/json { "age": 8, "breed": "chow" } Response HTTP/1.1 200 OK Content-Type: application/json { "age": 8, "breed": "chow", "tariffs": [ { "name": "Dog OP _ Basic", "rate": 12.4 } ] }
  • 29.
    REST API fürRechner funcmain() { r.HandleFunc("POST /api/quote", HandleQuote) } func HandleQuote(w http.ResponseWriter, r *http.Request) { 1 // 1. JSON Request lesen 2 var q Quote 3 json.NewDecoder(r.Body).Decode(&q) 4 5 // 2. Tarif berechnen 6 tariff := Tariff{Name: "Dog OP _ Basic", Rate: 12.4} 7 quote.Tariffs = []Tariff{tariff} 8 9 // 3. JSON Response schreiben 10 json.NewEncoder(w).Encode(quote) 11 } 12 13 14 r := http.NewServeMux() 15 16 17 18 r.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) { 19 w.Write([]byte("Hello DogOp!")) 20 }) 21 22 http.ListenAndServe(":8080", r) 23 24 func HandleQuote(w http.ResponseWriter, r *http.Request) { } 1 // 1. JSON Request lesen 2 var q Quote 3 json.NewDecoder(r.Body).Decode(&q) 4 5 // 2. Tarif berechnen 6 tariff := Tariff{Name: "Dog OP _ Basic", Rate: 12.4} 7 quote.Tariffs = []Tariff{tariff} 8 9 // 3. JSON Response schreiben 10 json.NewEncoder(w).Encode(quote) 11 12 13 func main() { 14 r := http.NewServeMux() 15 16 r.HandleFunc("POST /api/quote", HandleQuote) 17 18 r.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) { 19 w.Write([]byte("Hello DogOp!")) 20 }) 21 22 http.ListenAndServe(":8080", r) 23 } 24 // 1. JSON Request lesen var q Quote json.NewDecoder(r.Body).Decode(&q) func HandleQuote(w http.ResponseWriter, r *http.Request) { 1 2 3 4 5 // 2. Tarif berechnen 6 tariff := Tariff{Name: "Dog OP _ Basic", Rate: 12.4} 7 quote.Tariffs = []Tariff{tariff} 8 9 // 3. JSON Response schreiben 10 json.NewEncoder(w).Encode(quote) 11 } 12 13 func main() { 14 r := http.NewServeMux() 15 16 r.HandleFunc("POST /api/quote", HandleQuote) 17 18 r.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) { 19 w.Write([]byte("Hello DogOp!")) 20 }) 21 22 http.ListenAndServe(":8080", r) 23 } 24 // 2. Tarif berechnen tariff := Tariff{Name: "Dog OP _ Basic", Rate: 12.4} quote.Tariffs = []Tariff{tariff} func HandleQuote(w http.ResponseWriter, r *http.Request) { 1 // 1. JSON Request lesen 2 var q Quote 3 json.NewDecoder(r.Body).Decode(&q) 4 5 6 7 8 9 // 3. JSON Response schreiben 10 json.NewEncoder(w).Encode(quote) 11 } 12 13 func main() { 14 r := http.NewServeMux() 15 16 r.HandleFunc("POST /api/quote", HandleQuote) 17 18 r.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) { 19 w.Write([]byte("Hello DogOp!")) 20 }) 21 22 http.ListenAndServe(":8080", r) 23 } 24 // 3. JSON Response schreiben json.NewEncoder(w).Encode(quote) func HandleQuote(w http.ResponseWriter, r *http.Request) { 1 // 1. JSON Request lesen 2 var q Quote 3 json.NewDecoder(r.Body).Decode(&q) 4 5 // 2. Tarif berechnen 6 tariff := Tariff{Name: "Dog OP _ Basic", Rate: 12.4} 7 quote.Tariffs = []Tariff{tariff} 8 9 10 11 } 12 13 func main() { 14 r := http.NewServeMux() 15 16 r.HandleFunc("POST /api/quote", HandleQuote) 17 18 r.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) { 19 w.Write([]byte("Hello DogOp!")) 20 }) 21 22 http.ListenAndServe(":8080", r) 23 } 24 func HandleQuote(w http.ResponseWriter, r *http.Request) { // 1. JSON Request lesen var q Quote json.NewDecoder(r.Body).Decode(&q) // 2. Tarif berechnen tariff := Tariff{Name: "Dog OP _ Basic", Rate: 12.4} quote.Tariffs = []Tariff{tariff} // 3. JSON Response schreiben json.NewEncoder(w).Encode(quote) } func main() { r := http.NewServeMux() r.HandleFunc("POST /api/quote", HandleQuote) r.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello DogOp!")) }) http.ListenAndServe(":8080", r) } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Achtung, noch ohne Fehlerhandling! 💣
  • 31.
    Struct fürJSON type Tariffstruct { Name string `json:"name"` Rate float64 `json:"rate"` } 1 2 3 4 5 type Quote struct { 6 Age int `json:"age"` 7 Breed string `json:"breed"` 8 Tariffs []Tariff `json:"tariffs"` 9 } 10 type Quote struct { Age int `json:"age"` Breed string `json:"breed"` Tariffs []Tariff `json:"tariffs"` } type Tariff struct { 1 Name string `json:"name"` 2 Rate float64 `json:"rate"` 3 } 4 5 6 7 8 9 10 type Tariff struct { Name string `json:"name"` Rate float64 `json:"rate"` } type Quote struct { Age int `json:"age"` Breed string `json:"breed"` Tariffs []Tariff `json:"tariffs"` } 1 2 3 4 5 6 7 8 9 10 // Struct erzeugen tariff := Tariff{Name: "Dog OP _ Basic", Rate: 12.4}
  • 32.
    Fehler💣 func HandleQuote(w http.ResponseWriter,r *http.Request) { } 1 // 1. JSON Request lesen 2 var q Quote 3 json.NewDecoder(r.Body).Decode(&q) // 💣 Fehler möglich! 4 5 // 2. Tarif berechnen 6 tariff := Tariff{Name: "Dog OP _ Basic", Rate: 12.4} 7 quote.Tariffs = []Tariff{tariff} 8 9 // 3. JSON Response schreiben 10 json.NewEncoder(w).Encode(quote) // 💣 Fehler möglich! 11 12 json.NewDecoder(r.Body).Decode(&q) // 💣 Fehler möglich! json.NewEncoder(w).Encode(quote) // 💣 Fehler möglich! func HandleQuote(w http.ResponseWriter, r *http.Request) { 1 // 1. JSON Request lesen 2 var q Quote 3 4 5 // 2. Tarif berechnen 6 tariff := Tariff{Name: "Dog OP _ Basic", Rate: 12.4} 7 quote.Tariffs = []Tariff{tariff} 8 9 // 3. JSON Response schreiben 10 11 } 12
  • 34.
    Fehler💣 func HandleQuote(w http.ResponseWriter,r *http.Request) { } 1 // 1. JSON Request lesen 2 var q Quote 3 4 // Potentieller Fehler 5 err := json.NewDecoder(r.Body).Decode(&q) 6 7 // Auf Fehler prüfen 8 if err != nil { 9 // Fehler behandeln 10 http.Error(w, "Could not decode quote.😔", http.StatusBadRequest) 11 return 12 } 13 14 // ... 15 16 // Potentieller Fehler err := json.NewDecoder(r.Body).Decode(&q) func HandleQuote(w http.ResponseWriter, r *http.Request) { 1 // 1. JSON Request lesen 2 var q Quote 3 4 5 6 7 // Auf Fehler prüfen 8 if err != nil { 9 // Fehler behandeln 10 http.Error(w, "Could not decode quote.😔", http.StatusBadRequest) 11 return 12 } 13 14 // ... 15 } 16 // Auf Fehler prüfen if err != nil { } func HandleQuote(w http.ResponseWriter, r *http.Request) { 1 // 1. JSON Request lesen 2 var q Quote 3 4 // Potentieller Fehler 5 err := json.NewDecoder(r.Body).Decode(&q) 6 7 8 9 // Fehler behandeln 10 http.Error(w, "Could not decode quote.😔", http.StatusBadRequest) 11 return 12 13 14 // ... 15 } 16 func HandleQuote(w http.ResponseWriter, r *http.Request) { // 1. JSON Request lesen var q Quote // Potentieller Fehler err := json.NewDecoder(r.Body).Decode(&q) // Auf Fehler prüfen if err != nil { // Fehler behandeln http.Error(w, "Could not decode quote.😔", http.StatusBadRequest) return } // ... } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
  • 35.
    HTTPHandlertesten Unit Tests inStandardlib enthalten # Tests in Datei main_test.go #
  • 36.
    HTTPHandlertesten func TestHandleQuote(t *testing.T){ } 1 // 1. HTTP Recorder erstellen 2 recorder := httptest.NewRecorder() 3 4 // 2. Request erstellen (mit Body) 5 body := ` 6 { 7 "age": 8, 8 "breed": "chow" 9 } 10 ` 11 req, _ := http.NewRequest("GET", "/api/quote", strings.NewReader(body)) 12 13 // 3. Handler Funktion aufrufen 14 HandleQuote(recorder, req) 15 16 // 4. Return Code prüfen 17 if recorder.Code != http.StatusOK { 18 t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.StatusOK) 19 } 20 21 // 1. HTTP Recorder erstellen recorder := httptest.NewRecorder() func TestHandleQuote(t *testing.T) { 1 2 3 4 // 2. Request erstellen (mit Body) 5 body := ` 6 { 7 "age": 8, 8 "breed": "chow" 9 } 10 ` 11 req, _ := http.NewRequest("GET", "/api/quote", strings.NewReader(body)) 12 13 // 3. Handler Funktion aufrufen 14 HandleQuote(recorder, req) 15 16 // 4. Return Code prüfen 17 if recorder.Code != http.StatusOK { 18 t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.StatusOK) 19 } 20 } 21 // 2. Request erstellen (mit Body) body := ` { "age": 8, "breed": "chow" } ` req, _ := http.NewRequest("GET", "/api/quote", strings.NewReader(body)) func TestHandleQuote(t *testing.T) { 1 // 1. HTTP Recorder erstellen 2 recorder := httptest.NewRecorder() 3 4 5 6 7 8 9 10 11 12 13 // 3. Handler Funktion aufrufen 14 HandleQuote(recorder, req) 15 16 // 4. Return Code prüfen 17 if recorder.Code != http.StatusOK { 18 t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.StatusOK) 19 } 20 } 21 // 3. Handler Funktion aufrufen HandleQuote(recorder, req) func TestHandleQuote(t *testing.T) { 1 // 1. HTTP Recorder erstellen 2 recorder := httptest.NewRecorder() 3 4 // 2. Request erstellen (mit Body) 5 body := ` 6 { 7 "age": 8, 8 "breed": "chow" 9 } 10 ` 11 req, _ := http.NewRequest("GET", "/api/quote", strings.NewReader(body)) 12 13 14 15 16 // 4. Return Code prüfen 17 if recorder.Code != http.StatusOK { 18 t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.StatusOK) 19 } 20 } 21 // 4. Return Code prüfen if recorder.Code != http.StatusOK { t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.StatusOK) } func TestHandleQuote(t *testing.T) { 1 // 1. HTTP Recorder erstellen 2 recorder := httptest.NewRecorder() 3 4 // 2. Request erstellen (mit Body) 5 body := ` 6 { 7 "age": 8, 8 "breed": "chow" 9 } 10 ` 11 req, _ := http.NewRequest("GET", "/api/quote", strings.NewReader(body)) 12 13 // 3. Handler Funktion aufrufen 14 HandleQuote(recorder, req) 15 16 17 18 19 20 } 21 func TestHandleQuote(t *testing.T) { // 1. HTTP Recorder erstellen recorder := httptest.NewRecorder() // 2. Request erstellen (mit Body) body := ` { "age": 8, "breed": "chow" } ` req, _ := http.NewRequest("GET", "/api/quote", strings.NewReader(body)) // 3. Handler Funktion aufrufen HandleQuote(recorder, req) // 4. Return Code prüfen if recorder.Code != http.StatusOK { t.Errorf("Wrong status: got %v expected %v", recorder.Code, http.StatusOK) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
  • 37.
    HTTPHandlertesten go test -v./... === RUN TestHandleQuote --- PASS: TestHandleQuote (0.00s) PASS ok crossnative/dogop 0.228s
  • 38.
  • 39.
    Dockerfile fürDogOP # 1.DogOp Builder FROM golang as builder WORKDIR /app ADD . /app RUN CGO_ENABLED=0 go build -ldflags="-w -s" -o build/dogop . 1 2 3 4 5 6 # 2. DogOp Container 7 FROM alpine 8 COPY --from=builder /app/build/dogop /usr/bin/ 9 EXPOSE 8080 10 ENTRYPOINT ["/usr/bin/dogop"] 11 # 2. DogOp Container FROM alpine COPY --from=builder /app/build/dogop /usr/bin/ EXPOSE 8080 ENTRYPOINT ["/usr/bin/dogop"] # 1. DogOp Builder 1 FROM golang as builder 2 WORKDIR /app 3 ADD . /app 4 RUN CGO_ENABLED=0 go build -ldflags="-w -s" -o build/dogop . 5 6 7 8 9 10 11 # 1. DogOp Builder FROM golang as builder WORKDIR /app ADD . /app RUN CGO_ENABLED=0 go build -ldflags="-w -s" -o build/dogop . # 2. DogOp Container FROM alpine COPY --from=builder /app/build/dogop /usr/bin/ EXPOSE 8080 ENTRYPOINT ["/usr/bin/dogop"] 1 2 3 4 5 6 7 8 9 10 11
  • 40.
  • 41.
  • 42.
    Go Liebt Microservices ServerlessFunctions Kommandozeilen-Tools DevOps und Cloud
  • 43.
    3 Gründe fürGo 1.Einfach 2. Mächtig 3. Langweilig
  • 44.
  • 45.