From 0c2fefe360e5177602f5a822f99effafd4be8d81 Mon Sep 17 00:00:00 2001 From: Arne Bahlo Date: Fri, 1 Aug 2014 17:51:57 +0200 Subject: [PATCH] Split everything into files by responsibility --- goat.go | 22 ++------- index.go | 38 ++++++++++++++++ index_test.go | 23 ++++++++++ json.go | 26 +++++++++++ json_test.go | 1 + middleware.go | 26 +++++++++++ middleware_test.go | 16 +++++++ router.go | 108 +++++++++------------------------------------ router_test.go | 28 ------------ 9 files changed, 154 insertions(+), 134 deletions(-) create mode 100644 index.go create mode 100644 index_test.go create mode 100644 json.go create mode 100644 json_test.go create mode 100644 middleware.go create mode 100644 middleware_test.go diff --git a/goat.go b/goat.go index a44a37b..20c32c3 100644 --- a/goat.go +++ b/goat.go @@ -1,7 +1,6 @@ package goat import ( - "encoding/json" "net/http" "github.com/julienschmidt/httprouter" @@ -18,22 +17,7 @@ func New() *Router { return r } -// WriteError writes a string as JSON encoded error -func WriteError(w http.ResponseWriter, code int, err string) { - w.WriteHeader(code) - - WriteJSON(w, map[string]string{ - "error": err, - }) -} - -// WriteJSON writes the given interface as JSON or returns an error -func WriteJSON(w http.ResponseWriter, v interface{}) error { - b, err := json.MarshalIndent(v, "", " ") - if err != nil { - return err - } - - w.Write(b) - return nil +// Run starts the server +func (r *Router) Run(address string) error { + return http.ListenAndServe(address, r.chain()) } diff --git a/index.go b/index.go new file mode 100644 index 0000000..0cd6279 --- /dev/null +++ b/index.go @@ -0,0 +1,38 @@ +package goat + +import ( + "net/http" + "sort" +) + +// IndexHandler writes the index of all GET methods to the ResponseWriter +func (r *Router) IndexHandler(w http.ResponseWriter, _ *http.Request, _ Params) { + WriteJSON(w, r.Index()) +} + +// Index returns a string map with the titles and urls of all GET routes +func (r *Router) Index() map[string]string { + index := r.index + + // Recursion + for _, sr := range r.children { + si := sr.Index() + + for k, v := range si { + index[k] = v + } + } + + // Sort + sorted := make(map[string]string) + var keys []string + for k := range index { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + sorted[k] = index[k] + } + + return sorted +} diff --git a/index_test.go b/index_test.go new file mode 100644 index 0000000..e616e64 --- /dev/null +++ b/index_test.go @@ -0,0 +1,23 @@ +package goat + +import ( + "reflect" + "testing" +) + +func TestIndex(t *testing.T) { + r := New() + + r.Get("/foo/bar", "foo_bar_url", emptyHandler) + r.Get("/bar", "bar_url", emptyHandler) + r.Post("/foo", "foo_url", emptyHandler) + + out := r.Index() + expected := map[string]string{ + "bar_url": "/bar", + "foo_bar_url": "/foo/bar", + } + if !reflect.DeepEqual(out, expected) { + t.Errorf("Index should regurn %v, but did return %v", expected, out) + } +} diff --git a/json.go b/json.go new file mode 100644 index 0000000..9bdd56d --- /dev/null +++ b/json.go @@ -0,0 +1,26 @@ +package goat + +import ( + "encoding/json" + "net/http" +) + +// WriteError writes a string as JSON encoded error +func WriteError(w http.ResponseWriter, code int, err string) { + w.WriteHeader(code) + + WriteJSON(w, map[string]string{ + "error": err, + }) +} + +// WriteJSON writes the given interface as JSON or returns an error +func WriteJSON(w http.ResponseWriter, v interface{}) error { + b, err := json.MarshalIndent(v, "", " ") + if err != nil { + return err + } + + w.Write(b) + return nil +} diff --git a/json_test.go b/json_test.go new file mode 100644 index 0000000..b7f8451 --- /dev/null +++ b/json_test.go @@ -0,0 +1 @@ +package goat diff --git a/middleware.go b/middleware.go new file mode 100644 index 0000000..0b10949 --- /dev/null +++ b/middleware.go @@ -0,0 +1,26 @@ +package goat + +import "net/http" + +// Middleware reprents a default middleware function +type Middleware func(http.Handler) http.Handler + +// chain calls all middlewares and returns the final handler +func (r *Router) chain() http.Handler { + var final http.Handler + final = r.router + + for i := len(r.middleware) - 1; i >= 0; i-- { + final = r.middleware[i](final) + } + + return final +} + +// Use adds middleware to the router +func (r *Router) Use(middleware ...Middleware) { + if r.parent != nil { + panic("subrouters can't use middleware!") + } + r.middleware = append(r.middleware, middleware...) +} diff --git a/middleware_test.go b/middleware_test.go new file mode 100644 index 0000000..0008f1f --- /dev/null +++ b/middleware_test.go @@ -0,0 +1,16 @@ +package goat + +import ( + "net/http" + "testing" +) + +func TestUse(t *testing.T) { + r := New() + mw := func(h http.Handler) http.Handler { return nil } + //exp := []Middleware{mw} + + r.Use(mw) + + // TODO: Test function equality +} diff --git a/router.go b/router.go index 013d62e..c0c3381 100644 --- a/router.go +++ b/router.go @@ -2,7 +2,6 @@ package goat import ( "net/http" - "sort" "github.com/julienschmidt/httprouter" ) @@ -29,29 +28,19 @@ type Router struct { // Handle describes the function that should be used by handlers type Handle func(http.ResponseWriter, *http.Request, Params) -// Middleware reprents a default middleware function -type Middleware func(http.Handler) http.Handler - -// notFoundHandler handles (as you already know) the 404 error -func (r *Router) notFoundHandler(w http.ResponseWriter, req *http.Request) { - WriteError(w, 404, "404 Not Found") -} - -// ServeHTTP calls the same method on the router -func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { - r.router.ServeHTTP(w, req) -} - -// subPath returns the prefix of the router + the given path and eliminates -// duplicate slashes -func (r *Router) subPath(p string) string { - pre := r.prefix - - if (pre == "/" || pre[:len(pre)-1] == "/") && p[:1] == "/" { - pre = pre[:len(pre)-1] +// Subrouter creates and returns a subrouter +func (r *Router) Subrouter(path string) *Router { + sr := &Router{ + index: make(map[string]string), + prefix: r.subPath(path), + router: r.router, } - return pre + p + // Init relationships + r.children = append(r.children, sr) + sr.parent = r + + return sr } // addRoute adds a route to the index and passes it over to the httprouter @@ -93,74 +82,19 @@ func (r *Router) Put(path, title string, fn Handle) { r.addRoute("PUT", path, title, fn) } -// Subrouter creates and returns a subrouter -func (r *Router) Subrouter(path string) *Router { - sr := &Router{ - index: make(map[string]string), - prefix: r.subPath(path), - router: r.router, - } - - // Init relationships - r.children = append(r.children, sr) - sr.parent = r - - return sr -} - -// Use adds middleware to the router -func (r *Router) Use(middleware ...Middleware) { - if r.parent != nil { - panic("subrouters can't use middleware!") - } - r.middleware = append(r.middleware, middleware...) -} - -// Run starts the server -func (r *Router) Run(address string) error { - return http.ListenAndServe(address, r.chain()) -} - -// chain calls all middlewares and returns the final handler -func (r *Router) chain() http.Handler { - var final http.Handler - final = r.router - - for i := len(r.middleware) - 1; i >= 0; i-- { - final = r.middleware[i](final) - } - - return final -} - -// IndexHandler writes the index of all GET methods to the ResponseWriter -func (r *Router) IndexHandler(w http.ResponseWriter, _ *http.Request, _ Params) { - WriteJSON(w, r.Index()) +// notFoundHandler handles (as you already know) the 404 error +func (r *Router) notFoundHandler(w http.ResponseWriter, req *http.Request) { + WriteError(w, 404, "404 Not Found") } -// Index returns a string map with the titles and urls of all GET routes -func (r *Router) Index() map[string]string { - index := r.index - - // Recursion - for _, sr := range r.children { - si := sr.Index() - - for k, v := range si { - index[k] = v - } - } +// subPath returns the prefix of the router + the given path and eliminates +// duplicate slashes +func (r *Router) subPath(p string) string { + pre := r.prefix - // Sort - sorted := make(map[string]string) - var keys []string - for k := range index { - keys = append(keys, k) - } - sort.Strings(keys) - for _, k := range keys { - sorted[k] = index[k] + if (pre == "/" || pre[:len(pre)-1] == "/") && p[:1] == "/" { + pre = pre[:len(pre)-1] } - return sorted + return pre + p } diff --git a/router_test.go b/router_test.go index 6e121c7..df884e9 100644 --- a/router_test.go +++ b/router_test.go @@ -1,7 +1,6 @@ package goat import ( - "net/http" "reflect" "testing" ) @@ -37,23 +36,6 @@ func TestAddRoute(t *testing.T) { } } -func TestIndex(t *testing.T) { - r := New() - - r.Get("/foo/bar", "foo_bar_url", emptyHandler) - r.Get("/bar", "bar_url", emptyHandler) - r.Post("/foo", "foo_url", emptyHandler) - - out := r.Index() - expected := map[string]string{ - "bar_url": "/bar", - "foo_bar_url": "/foo/bar", - } - if !reflect.DeepEqual(out, expected) { - t.Errorf("Index should regurn %v, but did return %v", expected, out) - } -} - func TestSubrouter(t *testing.T) { pre := "/user" r := New() @@ -71,13 +53,3 @@ func TestSubrouter(t *testing.T) { t.Errorf("Subrouter should add %v to children of %v, but didn't", sr, r) } } - -func TestUse(t *testing.T) { - r := New() - mw := func(h http.Handler) http.Handler { return nil } - //exp := []Middleware{mw} - - r.Use(mw) - - // TODO: Test function equality -}