Skip to content

Commit 1577bf2

Browse files
committed
save initial work
0 parents  commit 1577bf2

10 files changed

+208
-0
lines changed

delete_repo.go

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
import (
3+
"database/sql"
4+
"fmt"
5+
)
6+
7+
// START OMIT
8+
func Delete(db *sql.DB, theStream *Stream) error {
9+
stmt, err := db.Prepare("DELETE FROM streams WHERE path = ?")
10+
if err != nil {
11+
return fmt.Errorf("could not prepare DELETE statement: %v", err)
12+
}
13+
14+
defer stmt.Close()
15+
_, err = stmt.Exec(theStream.Path)
16+
if err != nil {
17+
return fmt.Errorf("could not execute DELETE statement: %v", err)
18+
}
19+
20+
return nil
21+
}
22+
23+
// END OMIT

error_context.go

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import (
2+
"fmt"
3+
"os"
4+
)
5+
6+
// START OMIT
7+
func readConfig(configFile string) error {
8+
f, err := os.Open(configFile)
9+
if err != nil {
10+
return fmt.Errorf("could not read config from file %s: %v", configFile, err)
11+
}
12+
// do something with the open *File f
13+
}
14+
15+
// END OMIT

error_nocontext.go

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import (
2+
"os"
3+
)
4+
5+
// START OMIT
6+
func readConfig(configFile string) error {
7+
f, err := os.Open(configFile)
8+
if err != nil {
9+
return err
10+
}
11+
// do something with the open *File f
12+
}
13+
14+
// END OMIT

errorhttphandler.go

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import "net/http"
2+
3+
// START OMIT
4+
func (fn myHttpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
5+
if err := fn(w, r); err != nil {
6+
mylogger.Println(err)
7+
}
8+
}
9+
10+
http.Handle("/delete", appHandler(deleteStream(s, u)))
11+
// END OMIT

httphandler.go

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
func(http.ResponseWriter, *http.Request)

open.go

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
func Open(name string) (file *File, err error)

open_usage.go

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
f, err := os.Open("filename.ext")
2+
if err != nil {
3+
log.Fatal(err)
4+
}
5+
// do something with the open *File f

slides.slide

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
Error handling with Go
2+
3+
8 May 2018
4+
5+
6+
Frank Kleine
7+
8+
9+
10+
@bovigo
11+
12+
* Errors, what are they?
13+
14+
Errors can happen in each stage of the creation and execution of a program.
15+
16+
Error handling refers to the anticipation, detection, and resolution of
17+
programming, application, and communications errors.
18+
19+
From [[https://searchsoftwarequality.techtarget.com/definition/error-handling][What is error handling?]], Margaret Rouse
20+
21+
: Wikipedia offers "Exception handling only" - I don't like that.
22+
23+
* Errors in Go
24+
25+
From the os package, os.Open:
26+
.code open.go
27+
28+
And in usage it looks something like this:
29+
.code open_usage.go
30+
31+
Standard library is full of interesting examples. It's always worth to dive into it.
32+
33+
: Built-in error type. Golang.org blog article, a recommended read.
34+
35+
* Your errors
36+
37+
Always add context to an error before returning it.
38+
.code error_nocontext.go /START OMIT/,/END OMIT/
39+
vs.
40+
.code error_context.go /START OMIT/,/END OMIT/
41+
42+
* Errors in non end user functions
43+
44+
- E.g. functions that don't provide direct output to a user of a program.
45+
- Your backend functions, e.g. repositories, dealing with other services, etc.
46+
- Functions that most likely don't know how to deal with an error and must return immediately.
47+
48+
* Example: repository function
49+
50+
.code delete_repo.go /START OMIT/,/END OMIT/
51+
52+
* Errors in end user functions
53+
54+
- Functions that must provide direct output to a user
55+
- E.g. HTTP handlers, main func of a CLI program
56+
- Function must continue after the error happened to render some helpful output for the user (and hopefully log the error)
57+
58+
* Example: HTTP handler
59+
60+
- Default HTTP handler doesn't offer to return an error
61+
.code httphandler.go
62+
- Leads to repetitive code
63+
- Prevent this by specifying your own HTTP handler
64+
.code userhttphandler.go /START OMIT/,/END OMIT/
65+
- And a handler which handles the error
66+
.code errorhttphandler.go /START OMIT/,/END OMIT/
67+
68+
* User defined handler
69+
70+
.code userhandler.go /START OMIT/,/END OMIT/
71+
72+
* What about pkg/errors?
73+
74+
- A package by Dave Cheney, provides utility functions for working with errors.
75+
- Adds stack traces to errors
76+
- Uses chaining of errors, each error can have a cause
77+
78+
It's a great and interesting package. However, I never found the need in my code to add the weight of more code and dependencies for a perceived little gain.
79+
80+
(Disclaimer: Your mileage will vary.)
81+
82+
(Provoking opinion: if you need stack traces your code base in a single artefact is too large. Except when you ship a binary to a customer. Than you want stack traces.)
83+
84+
85+
* Links
86+
87+
- [[https://blog.golang.org/error-handling-and-go][Golang.org article about Go error handling]]
88+
- [[https://github.com/pkg/errors][pkg/errors]]

userhandler.go

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import (
2+
"fmt"
3+
"net/http"
4+
)
5+
// START OMIT
6+
func deleteStream(s Streams, u Upstream) myHttpHandler {
7+
return func(w *responseWriter, r *http.Request) (reterr error) {
8+
data := map[string]interface{}
9+
stream, err := s.FindByPath(r.URL.Path)
10+
if err != nil {
11+
w.WriteHeader(http.StatusInternalServerError)
12+
data["title"] = "Internal Server Error"
13+
data["error"] = "stream_lookup_error"
14+
reterr = fmt.Errorf("could not load stream %s from database: %v", r.URL.Path, err)
15+
} else if stream == nil {
16+
w.WriteHeader(http.StatusNotFound)
17+
data["title"] = "Not Found"
18+
data["error"] = "stream_does_not_exist"
19+
} else {
20+
data["title"] = stream.Title
21+
nowStreaming, err := u.NowStreaming(stream.Path)
22+
if err != nil {
23+
w.WriteHeader(http.StatusBadGateway)
24+
data["error"] = "stream_availability_error_not_sure_if_safe_to_delete"
25+
reterr = fmt.Errorf("failed to check availability for stream %q: %v", stream.Path, err)
26+
} else if nowStreaming {
27+
w.WriteHeader(http.StatusLocked)
28+
data["error"] = "stream_can_not_be_deleted_while_streaming"
29+
} else {
30+
err := s.Delete(stream)
31+
if err != nil {
32+
w.WriteHeader(http.StatusInternalServerError)
33+
data["error"] = "could_not_delete_stream"
34+
reterr = fmt.Errorf("failed to delete stream %q: %v", stream.Path, err)
35+
}
36+
}
37+
}
38+
39+
w.Render("deleted.gtmpl", data)
40+
return
41+
}
42+
}
43+
44+
// END OMIT

userhttphandler.go

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import "net/http"
2+
3+
// START OMIT
4+
type myHttpHandler func(http.ResponseWriter, *http.Request) error
5+
6+
// END OMIT

0 commit comments

Comments
 (0)