0

I need to define request handlers for specific requests in my Golang web server. The way I am doing this at present is as follows

package main

import "net/http"

type apiFunc func(rg string, w http.ResponseWriter, r *http.Request)

func h1(rg string, w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Bonjour"))
}

func h2(rg string, w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Guten Tag!"))
}

func h3(rg string, w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Good Morning!"))
}

type gHandlers map[string]apiFunc

var handlers gHandlers

func handleConnection(w http.ResponseWriter, r *http.Request) {
    hh := r.URL.Query().Get("handler")
    handlers[hh]("rg", w, r)
}

func main() {
    handlers = make(map[string]apiFunc, 3)
    handlers["h1"] = h1
    handlers["h2"] = h2
    handlers["h3"] = h3
    http.HandleFunc("/", handleConnection)
    http.ListenAndServe(":8080", nil)
}

This works just fine. However, I am still a newcomer to Golang so it may not be the "right" way to do things. I'd be much obliged to anyone who might be able to indicate whether is a better way to go about achieving this result

t j
  • 7,026
  • 12
  • 46
  • 66
DroidOS
  • 8,530
  • 16
  • 99
  • 171

1 Answers1

0

How about using a switch statement in handleConnection?

switch hh {
case "h1":
    h1("rg", w, r)
case "h2":
    h2("rg", w, r)
case "h3":
    h3("rg", w, r)
default:
    // return HTTP 400 here
}

The advantages are:

  • Simpler to understand code:
    • no apiFunc and gHandlers types
    • no need to browse around the source code in order to understand the routing logic, it is all in one place
  • More flexible: you can call functions with different arguments and implement more complex routing rules if necessary.
kostya
  • 9,221
  • 1
  • 29
  • 36
  • I generally tend to assume that a lookup table is faster than any kind of runtime conditional evaulation. This [SO thread](http://stackoverflow.com/questions/9928221/table-of-functions-vs-switch-in-golang) would appear to support that assumption. That apart all of my code is emitted by a script, not written by hand and it turns out to be cleaner/more efficient to emit a lookup table. – DroidOS Jul 10 '15 at 07:38
  • @DroidOS, the thread you mentioned is from 2012. It is possible that the latest Go compiler produces faster code. E.g. https://github.com/golang/go/commit/4bc9badd759f863f784e5f8d105a25c615324359 If performance is really important I would suggest you to benchmark two different approaches. – kostya Jul 10 '15 at 07:50
  • 1
    @DroidOS, if the code is auto-generated and no one looks at it other than Go compiler than I think it doesn't really matter if it is idiomatic or not. Just make it as efficient as possible. Look at stringer output for example (http://blog.golang.org/generate). – kostya Jul 10 '15 at 07:55
  • I just mentioned the possible speed issue in passing. The more important issue here is that emitting the lookup table is cleaner & faster than building a lengthy `switch` statement – DroidOS Jul 10 '15 at 07:56