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  }