route.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. package route
  2. import (
  3. "net/http"
  4. "github.com/julienschmidt/httprouter"
  5. "golang.org/x/net/context"
  6. )
  7. type param string
  8. // Param returns param p for the context.
  9. func Param(ctx context.Context, p string) string {
  10. return ctx.Value(param(p)).(string)
  11. }
  12. // WithParam returns a new context with param p set to v.
  13. func WithParam(ctx context.Context, p, v string) context.Context {
  14. return context.WithValue(ctx, param(p), v)
  15. }
  16. // Router wraps httprouter.Router and adds support for prefixed sub-routers
  17. // and per-request context injections.
  18. type Router struct {
  19. rtr *httprouter.Router
  20. prefix string
  21. }
  22. // New returns a new Router.
  23. func New() *Router {
  24. return &Router{
  25. rtr: httprouter.New(),
  26. }
  27. }
  28. // WithPrefix returns a router that prefixes all registered routes with prefix.
  29. func (r *Router) WithPrefix(prefix string) *Router {
  30. return &Router{rtr: r.rtr, prefix: r.prefix + prefix}
  31. }
  32. // handle turns a HandlerFunc into an httprouter.Handle.
  33. func (r *Router) handle(h http.HandlerFunc) httprouter.Handle {
  34. return func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
  35. ctx, cancel := context.WithCancel(req.Context())
  36. defer cancel()
  37. for _, p := range params {
  38. ctx = context.WithValue(ctx, param(p.Key), p.Value)
  39. }
  40. h(w, req.WithContext(ctx))
  41. }
  42. }
  43. // Get registers a new GET route.
  44. func (r *Router) Get(path string, h http.HandlerFunc) {
  45. r.rtr.GET(r.prefix+path, r.handle(h))
  46. }
  47. // Options registers a new OPTIONS route.
  48. func (r *Router) Options(path string, h http.HandlerFunc) {
  49. r.rtr.OPTIONS(r.prefix+path, r.handle(h))
  50. }
  51. // Del registers a new DELETE route.
  52. func (r *Router) Del(path string, h http.HandlerFunc) {
  53. r.rtr.DELETE(r.prefix+path, r.handle(h))
  54. }
  55. // Put registers a new PUT route.
  56. func (r *Router) Put(path string, h http.HandlerFunc) {
  57. r.rtr.PUT(r.prefix+path, r.handle(h))
  58. }
  59. // Post registers a new POST route.
  60. func (r *Router) Post(path string, h http.HandlerFunc) {
  61. r.rtr.POST(r.prefix+path, r.handle(h))
  62. }
  63. // Redirect takes an absolute path and sends an internal HTTP redirect for it,
  64. // prefixed by the router's path prefix. Note that this method does not include
  65. // functionality for handling relative paths or full URL redirects.
  66. func (r *Router) Redirect(w http.ResponseWriter, req *http.Request, path string, code int) {
  67. http.Redirect(w, req, r.prefix+path, code)
  68. }
  69. // ServeHTTP implements http.Handler.
  70. func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
  71. r.rtr.ServeHTTP(w, req)
  72. }
  73. // FileServe returns a new http.HandlerFunc that serves files from dir.
  74. // Using routes must provide the *filepath parameter.
  75. func FileServe(dir string) http.HandlerFunc {
  76. fs := http.FileServer(http.Dir(dir))
  77. return func(w http.ResponseWriter, r *http.Request) {
  78. r.URL.Path = Param(r.Context(), "filepath")
  79. fs.ServeHTTP(w, r)
  80. }
  81. }