github.com/best4tires/kit@v1.0.5/srv/router.go (about) 1 package srv 2 3 import ( 4 "fmt" 5 "net/http" 6 "reflect" 7 "strings" 8 9 "github.com/best4tires/kit/log" 10 "github.com/gorilla/mux" 11 ) 12 13 type IgnoreTrailingSlashes struct{} 14 15 // Var extract a variable formerly registered by {} from the request 16 func Var(r *http.Request, key string) string { 17 return mux.Vars(r)[key] 18 } 19 20 // Router encapsulates a http router 21 type Router struct { 22 mux *mux.Router 23 } 24 25 // NewRouter creates a new router 26 func NewRouter() *Router { 27 mr := mux.NewRouter() 28 mr.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 29 log.Warnf("not-found: %q", r.URL.String()) 30 http.Error(w, fmt.Sprintf("not-found %q", r.URL.Path), http.StatusNotFound) 31 }) 32 r := &Router{ 33 mux: mr, 34 } 35 return r 36 } 37 38 // WithPrefix return a prefix-router for the given prefix 39 func (r *Router) WithPrefix(prefix string) *PrefixRouter { 40 return &PrefixRouter{ 41 router: r, 42 prefix: prefix, 43 } 44 } 45 46 // Handler returns the http handler of the router 47 func (r *Router) Handler(mwares ...mux.MiddlewareFunc) http.Handler { 48 r.mux.Use(mwares...) 49 return r.mux 50 } 51 52 func (r *Router) containsOption(options []interface{}, opt interface{}) bool { 53 for _, o := range options { 54 if reflect.TypeOf(o) == reflect.TypeOf(opt) { 55 return true 56 } 57 } 58 return false 59 } 60 61 func (r *Router) patterns(s string, options ...interface{}) []string { 62 var ps []string 63 switch { 64 case r.containsOption(options, IgnoreTrailingSlashes{}): 65 p := strings.TrimSuffix(s, "/") 66 ps = append(ps, p, p+"/") 67 default: 68 ps = append(ps, s) 69 } 70 return ps 71 } 72 73 // GET registers a GET handler 74 func (r *Router) GET(pattern string, handle http.HandlerFunc, options ...interface{}) { 75 for _, p := range r.patterns(pattern, options...) { 76 log.Infof("route GET %q", p) 77 r.mux.Handle(p, handle).Methods("GET") 78 } 79 } 80 81 // POST registers a POST handler 82 func (r *Router) POST(pattern string, handle http.HandlerFunc, options ...interface{}) { 83 for _, p := range r.patterns(pattern, options...) { 84 log.Infof("route POST %q", p) 85 r.mux.Handle(p, handle).Methods("POST") 86 } 87 } 88 89 func (r *Router) PUT(pattern string, handle http.HandlerFunc, options ...interface{}) { 90 for _, p := range r.patterns(pattern, options...) { 91 log.Infof("route PUT %q", p) 92 r.mux.Handle(p, handle).Methods("PUT") 93 } 94 } 95 96 func (r *Router) DELETE(pattern string, handle http.HandlerFunc, options ...interface{}) { 97 for _, p := range r.patterns(pattern, options...) { 98 log.Infof("route DELETE %q", p) 99 r.mux.Handle(p, handle).Methods("DELETE") 100 } 101 } 102 103 func (r *Router) HEAD(pattern string, handle http.HandlerFunc, options ...interface{}) { 104 for _, p := range r.patterns(pattern, options...) { 105 log.Infof("route HEAD %q", p) 106 r.mux.Handle(p, handle).Methods("HEAD") 107 } 108 } 109 110 // PrefixGET registers a GET handler, which matches all routes with the given prefix 111 func (r *Router) PrefixGET(prefix string, handle http.HandlerFunc, options ...interface{}) { 112 r.mux.PathPrefix(prefix).HandlerFunc(handle).Methods("GET") 113 } 114 115 // PrefixPUT registers a PUT handler, which matches all routes with the given prefix 116 func (r *Router) PrefixPUT(prefix string, handle http.HandlerFunc, options ...interface{}) { 117 r.mux.PathPrefix(prefix).HandlerFunc(handle).Methods("PUT") 118 } 119 120 // PrefixPOST registers a POST handler, which matches all routes with the given prefix 121 func (r *Router) PrefixPOST(prefix string, handle http.HandlerFunc, options ...interface{}) { 122 r.mux.PathPrefix(prefix).HandlerFunc(handle).Methods("POST") 123 } 124 125 // PrefixDELETE registers a DELETE handler, which matches all routes with the given prefix 126 func (r *Router) PrefixDELETE(prefix string, handle http.HandlerFunc, options ...interface{}) { 127 r.mux.PathPrefix(prefix).HandlerFunc(handle).Methods("DELETE") 128 } 129 130 // PrefixHEAD registers a HEAD handler, which matches all routes with the given prefix 131 func (r *Router) PrefixHEAD(prefix string, handle http.HandlerFunc, options ...interface{}) { 132 r.mux.PathPrefix(prefix).HandlerFunc(handle).Methods("HEAD") 133 } 134 135 // PrefixGETHandler registers a GET handler, which matches all routes with the given prefix 136 func (r *Router) PrefixGETHandler(prefix string, handler http.Handler, options ...interface{}) { 137 r.mux.PathPrefix(prefix).Handler(handler).Methods("GET") 138 } 139 140 // PrefixPOSTHandler registers a POST handler, which matches all routes with the given prefix 141 func (r *Router) PrefixPOSTHandler(prefix string, handler http.Handler, options ...interface{}) { 142 r.mux.PathPrefix(prefix).Handler(handler).Methods("POST") 143 } 144 145 // PrefixRouter is a router, which routes prefixed routes 146 type PrefixRouter struct { 147 router *Router 148 prefix string 149 } 150 151 func (r *PrefixRouter) Resolve(pattern string) string { 152 return r.prefix + pattern 153 } 154 155 // GET registers a GET handler 156 func (r *PrefixRouter) GET(pattern string, handle http.HandlerFunc, options ...interface{}) { 157 r.router.GET(r.prefix+pattern, handle, options...) 158 } 159 160 // POST registers a POST handler 161 func (r *PrefixRouter) POST(pattern string, handle http.HandlerFunc, options ...interface{}) { 162 r.router.POST(r.prefix+pattern, handle, options...) 163 } 164 165 // PUT registers a PUT handler 166 func (r *PrefixRouter) PUT(pattern string, handle http.HandlerFunc, options ...interface{}) { 167 r.router.PUT(r.prefix+pattern, handle, options...) 168 } 169 170 // DELETE registers a DELETE handler 171 func (r *PrefixRouter) DELETE(pattern string, handle http.HandlerFunc, options ...interface{}) { 172 r.router.DELETE(r.prefix+pattern, handle, options...) 173 } 174 175 // HEAD registers a HEAD handler 176 func (r *PrefixRouter) HEAD(pattern string, handle http.HandlerFunc, options ...interface{}) { 177 r.router.HEAD(r.prefix+pattern, handle, options...) 178 } 179 180 // PrefixGET registers a GET handler, which matches all routes with the given prefix 181 func (r *PrefixRouter) PrefixGET(prefix string, handle http.HandlerFunc, options ...interface{}) { 182 r.router.PrefixGET(r.prefix+prefix, handle, options...) 183 } 184 185 func (r *PrefixRouter) WithPrefix(prefix string) *PrefixRouter { 186 return &PrefixRouter{ 187 router: r.router, 188 prefix: r.prefix + prefix, 189 } 190 } 191 192 func (r *PrefixRouter) Prefix() string { 193 return r.prefix 194 } 195 196 func (r *PrefixRouter) Handler(mwares ...mux.MiddlewareFunc) http.Handler { 197 r.router.mux.Use(mwares...) 198 return r.router.mux 199 }