2
\$\begingroup\$

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?

janos
113k15 gold badges154 silver badges396 bronze badges
asked May 11, 2015 at 15:29
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

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)
}
answered Mar 6, 2016 at 19:06
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.