Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: server/router/router.go

Issue 2043423004: Make HTTP middleware easier to use (Closed) Base URL: https://github.com/luci/luci-go@master
Patch Set: address Vadim's comments Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « server/router/handler.go ('k') | server/router/router_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 // Package router provides an HTTP router with support for middleware and
6 // subrouters. It wraps around julienschmidt/httprouter.
7 package router
8
9 import (
10 "net/http"
11 "strings"
12
13 "github.com/julienschmidt/httprouter"
14 "golang.org/x/net/context"
15 )
16
17 // Router is the main type for the package. To create a Router, use New.
18 type Router struct {
19 hrouter *httprouter.Router
20 middleware MiddlewareChain
21 BasePath string
22 }
23
24 // Context contains the context, response writer, request, and params shared
25 // across Middleware and Handler functions.
26 type Context struct {
27 context.Context
Vadim Sh. 2016/06/16 23:46:37 nit: new line after context.Context to separate em
nishanths 2016/06/17 00:48:24 Done.
28 Writer http.ResponseWriter
29 Request *http.Request
30 Params httprouter.Params
31 status int
32 }
33
34 var (
35 _ http.Handler = (*Router)(nil)
36 _ http.ResponseWriter = (*Context)(nil)
37 _ context.Context = (*Context)(nil)
38 )
39
40 // New creates a Router.
41 func New() *Router {
42 return &Router{
43 hrouter: httprouter.New(),
44 BasePath: "/",
45 }
46 }
47
48 // Use adds middleware chains to the group. The added middleware applies to
49 // all handlers registered on the router and to all handlers registered on
50 // routers that may be derived from the router (using Subrouter).
51 func (r *Router) Use(mc MiddlewareChain) {
52 r.middleware = append(r.middleware, mc...)
53 }
54
55 // Subrouter creates a new router with an updated base path.
56 // The new router copies middleware and configuration from the
57 // router it derives from.
58 func (r *Router) Subrouter(relativePath string) *Router {
59 newRouter := &Router{
60 hrouter: r.hrouter,
61 BasePath: makeBasePath(r.BasePath, relativePath),
62 }
63 if len(r.middleware) > 0 {
64 newRouter.middleware = make(MiddlewareChain, len(r.middleware))
65 copy(newRouter.middleware, r.middleware)
66 }
67 return newRouter
68 }
69
70 // GET is a shortcut for router.Handle("GET", path, mc, h)
71 func (r *Router) GET(path string, mc MiddlewareChain, h Handler) {
72 r.Handle("GET", path, mc, h)
73 }
74
75 // HEAD is a shortcut for router.Handle("HEAD", path, mc, h)
76 func (r *Router) HEAD(path string, mc MiddlewareChain, h Handler) {
77 r.Handle("HEAD", path, mc, h)
78 }
79
80 // OPTIONS is a shortcut for router.Handle("OPTIONS", path, mc, h)
81 func (r *Router) OPTIONS(path string, mc MiddlewareChain, h Handler) {
82 r.Handle("OPTIONS", path, mc, h)
83 }
84
85 // POST is a shortcut for router.Handle("POST", path, mc, h)
86 func (r *Router) POST(path string, mc MiddlewareChain, h Handler) {
87 r.Handle("POST", path, mc, h)
88 }
89
90 // PUT is a shortcut for router.Handle("PUT", path, mc, h)
91 func (r *Router) PUT(path string, mc MiddlewareChain, h Handler) {
92 r.Handle("PUT", path, mc, h)
93 }
94
95 // PATCH is a shortcut for router.Handle("PATCH", path, mc, h)
96 func (r *Router) PATCH(path string, mc MiddlewareChain, h Handler) {
97 r.Handle("PATCH", path, mc, h)
98 }
99
100 // DELETE is a shortcut for router.Handle("DELETE", path, mc, h)
101 func (r *Router) DELETE(path string, mc MiddlewareChain, h Handler) {
102 r.Handle("DELETE", path, mc, h)
103 }
104
105 // Handle registers a middleware chain and a handler for the given method and
106 // path. len(mc)==0 is allowed. See https://godoc.org/github.com/julienschmidt/h ttprouter
107 // for documentation on how the path may be formatted.
108 func (r *Router) Handle(method, path string, mc MiddlewareChain, h Handler) {
109 handle := r.adapt(mc, h)
110 r.hrouter.Handle(method, httprouter.CleanPath(r.BasePath+path), handle)
111 }
112
113 // ServeHTTP makes Router implement the http.Handler interface.
114 func (r *Router) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
115 r.hrouter.ServeHTTP(rw, req)
116 }
117
118 // adapt adapts given middleware chain and handler into a httprouter-style handl e.
119 func (r *Router) adapt(mc MiddlewareChain, h Handler) httprouter.Handle {
120 return httprouter.Handle(func(rw http.ResponseWriter, req *http.Request, p httprouter.Params) {
121 run(&Context{
122 Context: context.Background(),
123 Writer: rw,
124 Request: req,
125 Params: p,
126 }, r.middleware, mc, h)
127 })
128 }
129
130 func makeBasePath(base, relative string) string {
131 path := httprouter.CleanPath(base + relative)
132 if !strings.HasSuffix(path, "/") {
133 path += "/"
134 }
135 return path
136 }
137
138 // Header is used to implement http.ResponseWriter interface.
Vadim Sh. 2016/06/16 23:46:37 IMHO, it's better to remove this wrapping, since n
nodir 2016/06/17 00:25:04 (Chatted with Vadim) Indeed. If a middleware need
nishanths 2016/06/17 00:48:24 Sounds good. Done.
139 func (c *Context) Header() http.Header {
140 return c.Writer.Header()
141 }
142
143 // Write is used to implement http.ResponseWriter interface.
144 // If called from a Middleware function, the rules mentioned in the
145 // documentation for Middleware must be followed.
146 func (c *Context) Write(p []byte) (int, error) {
147 if !c.Written() {
148 c.status = http.StatusOK
149 }
150 return c.Writer.Write(p)
151 }
152
153 // WriteHeader is used to implement http.ResponseWriter interface.
154 // If called from a Middleware function, the rules mentioned in the
155 // documentation for Middleware must be followed.
156 func (c *Context) WriteHeader(code int) {
157 if !c.Written() {
158 c.status = code
159 }
160 c.Writer.WriteHeader(code)
161 }
162
163 // StatusCode returns the written HTTP status code or 0 if it was not written.
164 func (c *Context) StatusCode() int {
165 return c.status
166 }
167
168 // Written indicates whether a HTTP response has been written.
169 func (c *Context) Written() bool {
170 return c.status != 0
171 }
OLDNEW
« no previous file with comments | « server/router/handler.go ('k') | server/router/router_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698