Last active
July 23, 2018 17:44
-
-
Save fwojciec/8eda814d438710c2807abcf6adaa0125 to your computer and use it in GitHub Desktop.
My solution to "Exercise Setting headers only once + optional + super optional" from Section 03 of Francesc Campoy's Go Web Workshop
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://github.com/campoy/go-web-workshop/blob/master/section03/README.md | |
// Found these very helpful in the context of this exercise (optional tasks): | |
// 1. https://blog.questionable.services/article/custom-handlers-avoiding-globals/ | |
// 2. https://blog.questionable.services/article/http-handler-error-handling-revisited/ | |
package main | |
import ( | |
"errors" | |
"fmt" | |
"io/ioutil" | |
"log" | |
"net/http" | |
"strings" | |
) | |
type statusError struct { | |
Code int | |
Err error | |
} | |
// allows statusError to satisfy the error interface. | |
func (se statusError) Error() string { | |
return se.Err.Error() | |
} | |
// does what a handler does, but also returns an error | |
type customHandler func(http.ResponseWriter, *http.Request) error | |
// allows customHandler to satisfy http.Handler interface | |
func (f customHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |
w.Header().Set("Content-Type", "text/plain") | |
if err := f(w, r); err != nil { | |
switch e := err.(type) { | |
case statusError: | |
http.Error(w, e.Error(), e.Code) | |
default: | |
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) | |
} | |
} | |
} | |
func bodyHandler(w http.ResponseWriter, r *http.Request) error { | |
b, err := ioutil.ReadAll(r.Body) | |
if err != nil { | |
return statusError{500, errors.New("oops, couldn't read the body")} | |
} | |
name := strings.TrimSpace(string(b)) | |
if name == "" { | |
return statusError{400, errors.New("hey, the body can't be empty")} | |
} | |
fmt.Fprintf(w, "Hello, %s!", name) | |
return nil | |
} | |
func main() { | |
http.Handle("/hello", customHandler(bodyHandler)) | |
if err := http.ListenAndServe(":8080", nil); err != nil { | |
log.Fatal(err) | |
} | |
} |
@wmark Thanks Mark, great suggestion! Arguably an overkill in this particular case, but will definitely come back to your comment when I'm starting to work on something more serious as this approach makes makes reusing errors simple and elegant.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You can treat errors in a similar way: