2016-10-03 150 views
3

我在Go設計一個API服務器。我有許多數據庫表,每個表都有一個匹配的struct。每個人都有一個路由和處理程序:如何減少golang中重複的http處理程序代碼?

type Thing1 struct { 
    ID int64 
    Name string 
    ... 
} 

func main() { 
    ... 
    router := mux.NewRouter() 
    apiRouter := router.PathPrefix("/v1").Subrouter() 
    apiRouter.HandleFunc("/thing1/{id}", Thing1ShowHandler).Methods("GET") 
} 

func Thing1ShowHandler(w http.ResponseWriter, r *http.Request) { 
    vars := mux.Vars(r) 

    id, err := strconv.ParseInt(vars["id"], 10, 64) 
    if err != nil { 
     errorHandler(w, err) 
     return 
    } 
    thing1 := Thing1{ID: id} 
    err = db.First(&thing1, id).Error 
    if thing1.ID > 0 { 
     jsonHeaders(w, http.StatusOK) 
     if err := json.NewEncoder(w).Encode(thing1); err != nil { 
      errorHandler(w, err) 
     } 
     return 
    } 
    notFoundHandler(w, r) 
} 

Thing2的代碼幾乎是相同的,因爲它是爲Thing3等等。我最終會得到成百上千的東西,因此很多重複的代碼。感覺我正在做一些可怕的錯誤。什麼是使這個更乾的最好方法?

回答

3

爲什麼不爲每個Thing使用的http.Handler創建工廠功能?這允許您編寫一次showHandler邏輯並參數化個別事物的實例化。

// A ThingFactory returns a Thing struct configured with the given ID. 
type ThingFactory func(id int64) interface{} 

// The createShowHandler function is a factory function for creating a handler 
// which uses the getThing factory function to obtain an instance of a 
// thing to use when generating a view. 
func createShowHandler(getThing ThingFactory) http.HandlerFunc { 
    return func(w http.ResponseWriter, r *http.Request) { 
     vars := mux.Vars(r) 
     id, err := strconv.ParseInt(vars["id"], 10, 64) 

     if err != nil { 
      errorHandler(w, err) 
      return 
     } 

     thing := getThing(id) 
     err = db.First(&thing, id).Error 

     if err != nil { 
      errorHandler(w, err) 
     } 

     if thing1.ID > 0 { 
      jsonHeaders(w, http.StatusOK) 
      if err := json.NewEncoder(w).Encode(thing1); err != nil { 
       errorHandler(w, err) 
      } 
      return 
     } 

     notFoundHandler(w, r) 
    } 
} 

該函數可用於系統地爲給定路由器創建路由。例如,我可以創建一個顯式註冊表,用於跟蹤每個事物的路徑以及調用工廠函數createShowHandler時使用的實例。

router := mux.NewRouter() 
apiRouter := router.PathPrefix("/v1").Subrouter() 

registry := []struct { 
    path string 
    handler ThingFactory 
}{ 
    {"/thing1/{id}", func(id int64) interface{} { return Thing1{ID: id} }}, 
    {"/thing2/{id}", func(id int64) interface{} { return Thing2{ID: id} }}, 
    {"/thing3/{id}", func(id int64) interface{} { return Thing3{ID: id} }}, 
} 

for _, registrant := range registry { 
    apiRouter.HandleFunc(registrant.path, createShowHandler(registrant.handler)).Methods("GET") 
} 

當然,你想在這樣的程序有大量實例打交道時獲得更多的類型安全定義的各種交互點接口。可以實施更強大的註冊表,爲Thing提供註冊自己的界面。

+0

謝謝!我會試一試。 – Pippin