Last active
August 25, 2020 04:27
-
-
Save jiacai2050/b7445647006237f5fbb27cc2494ad3b0 to your computer and use it in GitHub Desktop.
A simple web app demonstrate how to deal with err in handler
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
package main | |
import ( | |
"bytes" | |
"errors" | |
"io" | |
"io/ioutil" | |
"log" | |
"net/http" | |
"os" | |
"os/signal" | |
"syscall" | |
) | |
type TodoApp struct { | |
addr string | |
// we can add some backend here | |
// db string | |
s *http.Server | |
} | |
func (a *TodoApp) Close() error { | |
log.Println("app closed...") | |
return a.s.Close() | |
} | |
func (a *TodoApp) Listen() error { | |
log.Printf("app start, listen on %s...\n", a.addr) | |
// maybe we can put handler registration when new TodoApp? | |
mux := http.NewServeMux() | |
mux.Handle("/", appHandler(a.list)) | |
mux.Handle("/about", appHandler(a.home)) | |
mux.Handle("/error", appHandler(a.error)) | |
a.s.Handler = mux | |
go func() { | |
sigs := make(chan os.Signal, 1) | |
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) | |
for { | |
sig := <-sigs | |
log.Printf("got close signal: %v", sig) | |
if err := a.Close(); err != nil { | |
log.Fatalf("stop all failed: %v", err) | |
} | |
} | |
}() | |
return a.s.ListenAndServe() | |
} | |
func (a *TodoApp) list(resp http.ResponseWriter, req *http.Request) AppResponse { | |
return SuccessString("this is a new todo list!") | |
} | |
func (a *TodoApp) home(resp http.ResponseWriter, req *http.Request) AppResponse { | |
return SuccessString("a todo app in construction") | |
} | |
func (a *TodoApp) error(resp http.ResponseWriter, req *http.Request) AppResponse { | |
return FailError(errors.New("a demo show how to deal with error")) | |
} | |
type AppResponse struct { | |
// required | |
status int | |
// optional | |
headers map[string]string | |
// body / err only one can be nil | |
body io.ReadCloser | |
err error | |
} | |
func SuccessString(body string) AppResponse { | |
return SuccessReader(ioutil.NopCloser(bytes.NewBufferString(body))) | |
} | |
func SuccessReader(r io.ReadCloser) AppResponse { | |
return AppResponse{ | |
status: 200, | |
body: r, | |
} | |
} | |
func FailError(e error) AppResponse { | |
return AppResponse{ | |
status: 500, | |
err: e, | |
} | |
} | |
type appHandler func(http.ResponseWriter, *http.Request) AppResponse | |
func (ah appHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { | |
ret := ah(resp, req) | |
resp.WriteHeader(ret.status) | |
hs := resp.Header() | |
for k, v := range ret.headers { | |
hs.Add(k, v) | |
} | |
if ret.err != nil { | |
if n, err := io.WriteString(resp, ret.err.Error()); err != nil { | |
log.Printf("write response failed %v, written: %d", err, n) | |
} | |
return | |
} | |
defer ret.body.Close() | |
if n, err := io.Copy(resp, ret.body); err != nil { | |
log.Printf("write response failed %v, written: %d", err, n) | |
} | |
} | |
func main() { | |
addr := ":11119" | |
app := &TodoApp{ | |
addr: addr, | |
s: &http.Server{Addr: addr}, | |
} | |
if err := app.Listen(); err != nil { | |
log.Fatal(err) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment