SlideShare ist ein Scribd-Unternehmen logo
1 von 38
Downloaden Sie, um offline zu lesen
GO WEB
DEVELOPMENT 101
3 MONTHS to be productive
74% write API SERVICES
45% write WEB APPS
*
Go Developer Survey 2020 Results
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
CATS APP 

API
SET UP CATS APP
# Create directory

mkdir cats

cd cats
# Enable dependency tracking

go mod init devopscon.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>
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"`

}
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
#
#
#
#
JAN STAMER
Solution Architect
jan.stamer@comdirect.de

Weitere ähnliche Inhalte

Was ist angesagt?

The Ring programming language version 1.5.3 book - Part 25 of 184
The Ring programming language version 1.5.3 book - Part 25 of 184The Ring programming language version 1.5.3 book - Part 25 of 184
The Ring programming language version 1.5.3 book - Part 25 of 184Mahmoud Samir Fayed
 
Are we ready to Go?
Are we ready to Go?Are we ready to Go?
Are we ready to Go?Adam Dudczak
 
clap: Command line argument parser for Pharo
clap: Command line argument parser for Pharoclap: Command line argument parser for Pharo
clap: Command line argument parser for PharoESUG
 
OSDC.TW - Gutscript for PHP haters
OSDC.TW - Gutscript for PHP hatersOSDC.TW - Gutscript for PHP haters
OSDC.TW - Gutscript for PHP hatersLin Yo-An
 
Dts x dicoding #2 memulai pemrograman kotlin
Dts x dicoding #2 memulai pemrograman kotlinDts x dicoding #2 memulai pemrograman kotlin
Dts x dicoding #2 memulai pemrograman kotlinAhmad Arif Faizin
 
2016年のPerl (Long version)
2016年のPerl (Long version)2016年のPerl (Long version)
2016年のPerl (Long version)charsbar
 
Unix Programming with Perl 2
Unix Programming with Perl 2Unix Programming with Perl 2
Unix Programming with Perl 2Kazuho Oku
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my dayTor Ivry
 
Code Generation in PHP - PHPConf 2015
Code Generation in PHP - PHPConf 2015Code Generation in PHP - PHPConf 2015
Code Generation in PHP - PHPConf 2015Lin Yo-An
 
The Ring programming language version 1.9 book - Part 37 of 210
The Ring programming language version 1.9 book - Part 37 of 210The Ring programming language version 1.9 book - Part 37 of 210
The Ring programming language version 1.9 book - Part 37 of 210Mahmoud Samir Fayed
 

Was ist angesagt? (20)

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

Ähnlich wie Go Web Development 101: Build a Cat API and App in 3 Months

Ch ch-changes cake php2
Ch ch-changes cake php2Ch ch-changes cake php2
Ch ch-changes cake php2markstory
 
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+ConFoo
 
Jersey framework
Jersey frameworkJersey framework
Jersey frameworkknight1128
 
¿Cómo de sexy puede hacer Backbone mi código?
¿Cómo de sexy puede hacer Backbone mi código?¿Cómo de sexy puede hacer Backbone mi código?
¿Cómo de sexy puede hacer Backbone mi código?jaespinmora
 
Practical JavaScript Programming - Session 7/8
Practical JavaScript Programming - Session 7/8Practical JavaScript Programming - Session 7/8
Practical JavaScript Programming - Session 7/8Wilson Su
 
ECMeowScript - What's New in JavaScript Explained with Cats (August 14th, 2020)
ECMeowScript - What's New in JavaScript Explained with Cats (August 14th, 2020)ECMeowScript - What's New in JavaScript Explained with Cats (August 14th, 2020)
ECMeowScript - What's New in JavaScript Explained with Cats (August 14th, 2020)Tomomi Imura
 
Building and Incredible Machine with Pipelines and Generators in PHP (IPC Ber...
Building and Incredible Machine with Pipelines and Generators in PHP (IPC Ber...Building and Incredible Machine with Pipelines and Generators in PHP (IPC Ber...
Building and Incredible Machine with Pipelines and Generators in PHP (IPC Ber...dantleech
 
Java9 Beyond Modularity - Java 9 más allá de la modularidad
Java9 Beyond Modularity - Java 9 más allá de la modularidadJava9 Beyond Modularity - Java 9 más allá de la modularidad
Java9 Beyond Modularity - Java 9 más allá de la modularidadDavid Gómez García
 
Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516SOAT
 
Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers StealBen Scofield
 
Finch.io - Purely Functional REST API with Finagle
Finch.io - Purely Functional REST API with FinagleFinch.io - Purely Functional REST API with Finagle
Finch.io - Purely Functional REST API with FinagleVladimir Kostyukov
 
Adding 1.21 Gigawatts to Applications with RabbitMQ (DPC 2015)
Adding 1.21 Gigawatts to Applications with RabbitMQ (DPC 2015)Adding 1.21 Gigawatts to Applications with RabbitMQ (DPC 2015)
Adding 1.21 Gigawatts to Applications with RabbitMQ (DPC 2015)James Titcumb
 
Practical JavaScript Programming - Session 5/8
Practical JavaScript Programming - Session 5/8Practical JavaScript Programming - Session 5/8
Practical JavaScript Programming - Session 5/8Wilson Su
 
Node Boot Camp
Node Boot CampNode Boot Camp
Node Boot CampTroy Miles
 
Whats new in_csharp4
Whats new in_csharp4Whats new in_csharp4
Whats new in_csharp4Abed Bukhari
 
Let's build a 0-cost invite-only website with Next.js and Airtable!
Let's build a 0-cost invite-only website with Next.js and Airtable!Let's build a 0-cost invite-only website with Next.js and Airtable!
Let's build a 0-cost invite-only website with Next.js and Airtable!Luciano Mammino
 
Workshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScriptWorkshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScriptVisual Engineering
 
java compilerCompiler1.javajava compilerCompiler1.javaimport.docx
java compilerCompiler1.javajava compilerCompiler1.javaimport.docxjava compilerCompiler1.javajava compilerCompiler1.javaimport.docx
java compilerCompiler1.javajava compilerCompiler1.javaimport.docxpriestmanmable
 

Ähnlich wie Go Web Development 101: Build a Cat API and App in 3 Months (20)

Ch ch-changes cake php2
Ch ch-changes cake php2Ch ch-changes cake php2
Ch ch-changes cake php2
 
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
 
Jersey framework
Jersey frameworkJersey framework
Jersey framework
 
¿Cómo de sexy puede hacer Backbone mi código?
¿Cómo de sexy puede hacer Backbone mi código?¿Cómo de sexy puede hacer Backbone mi código?
¿Cómo de sexy puede hacer Backbone mi código?
 
Practical JavaScript Programming - Session 7/8
Practical JavaScript Programming - Session 7/8Practical JavaScript Programming - Session 7/8
Practical JavaScript Programming - Session 7/8
 
ECMeowScript - What's New in JavaScript Explained with Cats (August 14th, 2020)
ECMeowScript - What's New in JavaScript Explained with Cats (August 14th, 2020)ECMeowScript - What's New in JavaScript Explained with Cats (August 14th, 2020)
ECMeowScript - What's New in JavaScript Explained with Cats (August 14th, 2020)
 
Building and Incredible Machine with Pipelines and Generators in PHP (IPC Ber...
Building and Incredible Machine with Pipelines and Generators in PHP (IPC Ber...Building and Incredible Machine with Pipelines and Generators in PHP (IPC Ber...
Building and Incredible Machine with Pipelines and Generators in PHP (IPC Ber...
 
Java9 Beyond Modularity - Java 9 más allá de la modularidad
Java9 Beyond Modularity - Java 9 más allá de la modularidadJava9 Beyond Modularity - Java 9 más allá de la modularidad
Java9 Beyond Modularity - Java 9 más allá de la modularidad
 
Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516
 
Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers Steal
 
Finch.io - Purely Functional REST API with Finagle
Finch.io - Purely Functional REST API with FinagleFinch.io - Purely Functional REST API with Finagle
Finch.io - Purely Functional REST API with Finagle
 
Adding 1.21 Gigawatts to Applications with RabbitMQ (DPC 2015)
Adding 1.21 Gigawatts to Applications with RabbitMQ (DPC 2015)Adding 1.21 Gigawatts to Applications with RabbitMQ (DPC 2015)
Adding 1.21 Gigawatts to Applications with RabbitMQ (DPC 2015)
 
Practical JavaScript Programming - Session 5/8
Practical JavaScript Programming - Session 5/8Practical JavaScript Programming - Session 5/8
Practical JavaScript Programming - Session 5/8
 
Node Boot Camp
Node Boot CampNode Boot Camp
Node Boot Camp
 
Whats new in_csharp4
Whats new in_csharp4Whats new in_csharp4
Whats new in_csharp4
 
Let's build a 0-cost invite-only website with Next.js and Airtable!
Let's build a 0-cost invite-only website with Next.js and Airtable!Let's build a 0-cost invite-only website with Next.js and Airtable!
Let's build a 0-cost invite-only website with Next.js and Airtable!
 
Workshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScriptWorkshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScript
 
java compilerCompiler1.javajava compilerCompiler1.javaimport.docx
java compilerCompiler1.javajava compilerCompiler1.javaimport.docxjava compilerCompiler1.javajava compilerCompiler1.javaimport.docx
java compilerCompiler1.javajava compilerCompiler1.javaimport.docx
 
My java file
My java fileMy java file
My java file
 
Server1
Server1Server1
Server1
 

Mehr von Jan Stamer

JAX 2024: Go-über-den-Wolken und in der Cloud
JAX 2024: Go-über-den-Wolken und in der CloudJAX 2024: Go-über-den-Wolken und in der Cloud
JAX 2024: Go-über-den-Wolken und in der CloudJan Stamer
 
JAX 2024: Go in der Praxis einsetzen
JAX 2024: Go in der Praxis einsetzenJAX 2024: Go in der Praxis einsetzen
JAX 2024: Go in der Praxis einsetzenJan Stamer
 
W-JAX 2023: Go über den Wolken
W-JAX 2023: Go über den WolkenW-JAX 2023: Go über den Wolken
W-JAX 2023: Go über den WolkenJan Stamer
 
CloudLand 2023: Rock, Paper, Scissors Cloud Competition - Go vs. Java
CloudLand 2023: Rock, Paper, Scissors Cloud Competition - Go vs. JavaCloudLand 2023: Rock, Paper, Scissors Cloud Competition - Go vs. Java
CloudLand 2023: Rock, Paper, Scissors Cloud Competition - Go vs. JavaJan Stamer
 
entwickler.de 05/2023: Go über den Wolken
entwickler.de 05/2023: Go über den Wolkenentwickler.de 05/2023: Go über den Wolken
entwickler.de 05/2023: Go über den WolkenJan Stamer
 
IT-Tage 2021: Java to Go - Google Go für Java-Entwickler
IT-Tage 2021: Java to Go - Google Go für Java-Entwickler IT-Tage 2021: Java to Go - Google Go für Java-Entwickler
IT-Tage 2021: Java to Go - Google Go für Java-Entwickler Jan Stamer
 
entwickler.de Go Day: Go Web Development 101
entwickler.de Go Day: Go Web Development 101entwickler.de Go Day: Go Web Development 101
entwickler.de Go Day: Go Web Development 101Jan Stamer
 
JCON 2021: Turbo powered Web Apps
JCON 2021: Turbo powered Web AppsJCON 2021: Turbo powered Web Apps
JCON 2021: Turbo powered Web AppsJan Stamer
 
Karlsruher Entwicklertag 2021: Turbo powered Web Apps
Karlsruher Entwicklertag 2021: Turbo powered Web AppsKarlsruher Entwicklertag 2021: Turbo powered Web Apps
Karlsruher Entwicklertag 2021: Turbo powered Web AppsJan Stamer
 
Jugs HH: Elefant unter Strom - von OldSQL über NoSQL zu NewSQL?
Jugs HH: Elefant unter Strom - von OldSQL über NoSQL zu NewSQL?Jugs HH: Elefant unter Strom - von OldSQL über NoSQL zu NewSQL?
Jugs HH: Elefant unter Strom - von OldSQL über NoSQL zu NewSQL?Jan Stamer
 

Mehr von Jan Stamer (10)

JAX 2024: Go-über-den-Wolken und in der Cloud
JAX 2024: Go-über-den-Wolken und in der CloudJAX 2024: Go-über-den-Wolken und in der Cloud
JAX 2024: Go-über-den-Wolken und in der Cloud
 
JAX 2024: Go in der Praxis einsetzen
JAX 2024: Go in der Praxis einsetzenJAX 2024: Go in der Praxis einsetzen
JAX 2024: Go in der Praxis einsetzen
 
W-JAX 2023: Go über den Wolken
W-JAX 2023: Go über den WolkenW-JAX 2023: Go über den Wolken
W-JAX 2023: Go über den Wolken
 
CloudLand 2023: Rock, Paper, Scissors Cloud Competition - Go vs. Java
CloudLand 2023: Rock, Paper, Scissors Cloud Competition - Go vs. JavaCloudLand 2023: Rock, Paper, Scissors Cloud Competition - Go vs. Java
CloudLand 2023: Rock, Paper, Scissors Cloud Competition - Go vs. Java
 
entwickler.de 05/2023: Go über den Wolken
entwickler.de 05/2023: Go über den Wolkenentwickler.de 05/2023: Go über den Wolken
entwickler.de 05/2023: Go über den Wolken
 
IT-Tage 2021: Java to Go - Google Go für Java-Entwickler
IT-Tage 2021: Java to Go - Google Go für Java-Entwickler IT-Tage 2021: Java to Go - Google Go für Java-Entwickler
IT-Tage 2021: Java to Go - Google Go für Java-Entwickler
 
entwickler.de Go Day: Go Web Development 101
entwickler.de Go Day: Go Web Development 101entwickler.de Go Day: Go Web Development 101
entwickler.de Go Day: Go Web Development 101
 
JCON 2021: Turbo powered Web Apps
JCON 2021: Turbo powered Web AppsJCON 2021: Turbo powered Web Apps
JCON 2021: Turbo powered Web Apps
 
Karlsruher Entwicklertag 2021: Turbo powered Web Apps
Karlsruher Entwicklertag 2021: Turbo powered Web AppsKarlsruher Entwicklertag 2021: Turbo powered Web Apps
Karlsruher Entwicklertag 2021: Turbo powered Web Apps
 
Jugs HH: Elefant unter Strom - von OldSQL über NoSQL zu NewSQL?
Jugs HH: Elefant unter Strom - von OldSQL über NoSQL zu NewSQL?Jugs HH: Elefant unter Strom - von OldSQL über NoSQL zu NewSQL?
Jugs HH: Elefant unter Strom - von OldSQL über NoSQL zu NewSQL?
 

Kürzlich hochgeladen

From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...gurkirankumar98700
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Google AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGGoogle AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGSujit Pal
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 

Kürzlich hochgeladen (20)

From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Google AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGGoogle AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAG
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 

Go Web Development 101: Build a Cat API and App in 3 Months

  • 2. 3 MONTHS to be productive 74% write API SERVICES 45% write WEB APPS * Go Developer Survey 2020 Results
  • 3.
  • 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
  • 11.
  • 13. SET UP CATS APP # Create directory mkdir cats cd cats # Enable dependency tracking go mod init devopscon.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>
  • 29.
  • 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"` }
  • 31.
  • 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 # # # #
  • 37.