The challenge, from Tour of Go, "Exercise: HTTP Handlers":
Implement the following types and define ServeHTTP methods on them. Register them to handle specific paths in your web server.
type String string
type Struct struct {
Greeting string
Punct string
Who string
}
For example, you should be able to register handlers using:
http.Handle("/string", String("I'm a frayed knot."))
http.Handle("/struct", &Struct{"Hello", ":", "Gophers!"})
Solution:
package main
import (
"log"
"net/http"
"fmt"
)
type String string
type Struct struct {
Greeting string
Punct string
Who string
}
func (s String) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if _, err := fmt.Fprint(w, s); err != nil {
log.Fatal("Error in ServerHTTP of String.")
}
}
func (s *Struct) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if _, err := fmt.Fprint(w, s.Greeting, s.Punct, s.Who); err != nil {
log.Fatal("Error in ServerHTTP of String.")
}
}
func main() {
http.Handle("/string", String("I'm a frayed knot."))
http.Handle("/struct", &Struct{"Hello", ":", "Gophers!"})
log.Fatal(http.ListenAndServe("localhost:4000", nil))
}
Any suggestions on how to improve this code?
1 Answer 1
The logic of trying to write or else log.Fatal
is duplicated in the two ServeHTTP
implementations. And the log message looks copy pasted, because it's the same for both the String
and *Struct
versions, for example:
func (s *Struct) ServeHTTP(w http.ResponseWriter, r *http.Request) { if _, err := fmt.Fprint(w, s.Greeting, s.Punct, s.Who); err != nil { log.Fatal("Error in ServerHTTP of String.") } }
You could extract the common logic to a function, for example:
func writeOrElseLogFatal(writer func() (int, error), msg string) {
if _, err := writer(); err != nil {
log.Fatalf("Error in ServeHTTP of %s", msg)
}
}
And then call it like this, for example for *Struct
:
func (s *Struct) ServeHTTP(w http.ResponseWriter, r *http.Request) {
writer := func() (int, error) {
return fmt.Fprint(w, s.Greeting, s.Punct, s.Who)
}
writeOrElseLogFatal(writer, "Struct")
}
Or you could make things simpler by not logging at all in these functions:
func (s String) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, s)
}
func (s *Struct) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, s.Greeting, s.Punct, s.Who)
}
Explore related questions
See similar questions with these tags.