Use vendored dependencies
[bloat] / vendor / github.com / gorilla / mux / doc.go
1 // Copyright 2012 The Gorilla Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 /*
6 Package mux implements a request router and dispatcher.
7
8 The name mux stands for "HTTP request multiplexer". Like the standard
9 http.ServeMux, mux.Router matches incoming requests against a list of
10 registered routes and calls a handler for the route that matches the URL
11 or other conditions. The main features are:
12
13         * Requests can be matched based on URL host, path, path prefix, schemes,
14           header and query values, HTTP methods or using custom matchers.
15         * URL hosts, paths and query values can have variables with an optional
16           regular expression.
17         * Registered URLs can be built, or "reversed", which helps maintaining
18           references to resources.
19         * Routes can be used as subrouters: nested routes are only tested if the
20           parent route matches. This is useful to define groups of routes that
21           share common conditions like a host, a path prefix or other repeated
22           attributes. As a bonus, this optimizes request matching.
23         * It implements the http.Handler interface so it is compatible with the
24           standard http.ServeMux.
25
26 Let's start registering a couple of URL paths and handlers:
27
28         func main() {
29                 r := mux.NewRouter()
30                 r.HandleFunc("/", HomeHandler)
31                 r.HandleFunc("/products", ProductsHandler)
32                 r.HandleFunc("/articles", ArticlesHandler)
33                 http.Handle("/", r)
34         }
35
36 Here we register three routes mapping URL paths to handlers. This is
37 equivalent to how http.HandleFunc() works: if an incoming request URL matches
38 one of the paths, the corresponding handler is called passing
39 (http.ResponseWriter, *http.Request) as parameters.
40
41 Paths can have variables. They are defined using the format {name} or
42 {name:pattern}. If a regular expression pattern is not defined, the matched
43 variable will be anything until the next slash. For example:
44
45         r := mux.NewRouter()
46         r.HandleFunc("/products/{key}", ProductHandler)
47         r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
48         r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
49
50 Groups can be used inside patterns, as long as they are non-capturing (?:re). For example:
51
52         r.HandleFunc("/articles/{category}/{sort:(?:asc|desc|new)}", ArticlesCategoryHandler)
53
54 The names are used to create a map of route variables which can be retrieved
55 calling mux.Vars():
56
57         vars := mux.Vars(request)
58         category := vars["category"]
59
60 Note that if any capturing groups are present, mux will panic() during parsing. To prevent
61 this, convert any capturing groups to non-capturing, e.g. change "/{sort:(asc|desc)}" to
62 "/{sort:(?:asc|desc)}". This is a change from prior versions which behaved unpredictably
63 when capturing groups were present.
64
65 And this is all you need to know about the basic usage. More advanced options
66 are explained below.
67
68 Routes can also be restricted to a domain or subdomain. Just define a host
69 pattern to be matched. They can also have variables:
70
71         r := mux.NewRouter()
72         // Only matches if domain is "www.example.com".
73         r.Host("www.example.com")
74         // Matches a dynamic subdomain.
75         r.Host("{subdomain:[a-z]+}.domain.com")
76
77 There are several other matchers that can be added. To match path prefixes:
78
79         r.PathPrefix("/products/")
80
81 ...or HTTP methods:
82
83         r.Methods("GET", "POST")
84
85 ...or URL schemes:
86
87         r.Schemes("https")
88
89 ...or header values:
90
91         r.Headers("X-Requested-With", "XMLHttpRequest")
92
93 ...or query values:
94
95         r.Queries("key", "value")
96
97 ...or to use a custom matcher function:
98
99         r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
100                 return r.ProtoMajor == 0
101         })
102
103 ...and finally, it is possible to combine several matchers in a single route:
104
105         r.HandleFunc("/products", ProductsHandler).
106           Host("www.example.com").
107           Methods("GET").
108           Schemes("http")
109
110 Setting the same matching conditions again and again can be boring, so we have
111 a way to group several routes that share the same requirements.
112 We call it "subrouting".
113
114 For example, let's say we have several URLs that should only match when the
115 host is "www.example.com". Create a route for that host and get a "subrouter"
116 from it:
117
118         r := mux.NewRouter()
119         s := r.Host("www.example.com").Subrouter()
120
121 Then register routes in the subrouter:
122
123         s.HandleFunc("/products/", ProductsHandler)
124         s.HandleFunc("/products/{key}", ProductHandler)
125         s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
126
127 The three URL paths we registered above will only be tested if the domain is
128 "www.example.com", because the subrouter is tested first. This is not
129 only convenient, but also optimizes request matching. You can create
130 subrouters combining any attribute matchers accepted by a route.
131
132 Subrouters can be used to create domain or path "namespaces": you define
133 subrouters in a central place and then parts of the app can register its
134 paths relatively to a given subrouter.
135
136 There's one more thing about subroutes. When a subrouter has a path prefix,
137 the inner routes use it as base for their paths:
138
139         r := mux.NewRouter()
140         s := r.PathPrefix("/products").Subrouter()
141         // "/products/"
142         s.HandleFunc("/", ProductsHandler)
143         // "/products/{key}/"
144         s.HandleFunc("/{key}/", ProductHandler)
145         // "/products/{key}/details"
146         s.HandleFunc("/{key}/details", ProductDetailsHandler)
147
148 Note that the path provided to PathPrefix() represents a "wildcard": calling
149 PathPrefix("/static/").Handler(...) means that the handler will be passed any
150 request that matches "/static/*". This makes it easy to serve static files with mux:
151
152         func main() {
153                 var dir string
154
155                 flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
156                 flag.Parse()
157                 r := mux.NewRouter()
158
159                 // This will serve files under http://localhost:8000/static/<filename>
160                 r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
161
162                 srv := &http.Server{
163                         Handler:      r,
164                         Addr:         "127.0.0.1:8000",
165                         // Good practice: enforce timeouts for servers you create!
166                         WriteTimeout: 15 * time.Second,
167                         ReadTimeout:  15 * time.Second,
168                 }
169
170                 log.Fatal(srv.ListenAndServe())
171         }
172
173 Now let's see how to build registered URLs.
174
175 Routes can be named. All routes that define a name can have their URLs built,
176 or "reversed". We define a name calling Name() on a route. For example:
177
178         r := mux.NewRouter()
179         r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
180           Name("article")
181
182 To build a URL, get the route and call the URL() method, passing a sequence of
183 key/value pairs for the route variables. For the previous route, we would do:
184
185         url, err := r.Get("article").URL("category", "technology", "id", "42")
186
187 ...and the result will be a url.URL with the following path:
188
189         "/articles/technology/42"
190
191 This also works for host and query value variables:
192
193         r := mux.NewRouter()
194         r.Host("{subdomain}.domain.com").
195           Path("/articles/{category}/{id:[0-9]+}").
196           Queries("filter", "{filter}").
197           HandlerFunc(ArticleHandler).
198           Name("article")
199
200         // url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla"
201         url, err := r.Get("article").URL("subdomain", "news",
202                                          "category", "technology",
203                                          "id", "42",
204                                          "filter", "gorilla")
205
206 All variables defined in the route are required, and their values must
207 conform to the corresponding patterns. These requirements guarantee that a
208 generated URL will always match a registered route -- the only exception is
209 for explicitly defined "build-only" routes which never match.
210
211 Regex support also exists for matching Headers within a route. For example, we could do:
212
213         r.HeadersRegexp("Content-Type", "application/(text|json)")
214
215 ...and the route will match both requests with a Content-Type of `application/json` as well as
216 `application/text`
217
218 There's also a way to build only the URL host or path for a route:
219 use the methods URLHost() or URLPath() instead. For the previous route,
220 we would do:
221
222         // "http://news.domain.com/"
223         host, err := r.Get("article").URLHost("subdomain", "news")
224
225         // "/articles/technology/42"
226         path, err := r.Get("article").URLPath("category", "technology", "id", "42")
227
228 And if you use subrouters, host and path defined separately can be built
229 as well:
230
231         r := mux.NewRouter()
232         s := r.Host("{subdomain}.domain.com").Subrouter()
233         s.Path("/articles/{category}/{id:[0-9]+}").
234           HandlerFunc(ArticleHandler).
235           Name("article")
236
237         // "http://news.domain.com/articles/technology/42"
238         url, err := r.Get("article").URL("subdomain", "news",
239                                          "category", "technology",
240                                          "id", "42")
241
242 Mux supports the addition of middlewares to a Router, which are executed in the order they are added if a match is found, including its subrouters. Middlewares are (typically) small pieces of code which take one request, do something with it, and pass it down to another middleware or the final handler. Some common use cases for middleware are request logging, header manipulation, or ResponseWriter hijacking.
243
244         type MiddlewareFunc func(http.Handler) http.Handler
245
246 Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc (closures can access variables from the context where they are created).
247
248 A very basic middleware which logs the URI of the request being handled could be written as:
249
250         func simpleMw(next http.Handler) http.Handler {
251                 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
252                         // Do stuff here
253                         log.Println(r.RequestURI)
254                         // Call the next handler, which can be another middleware in the chain, or the final handler.
255                         next.ServeHTTP(w, r)
256                 })
257         }
258
259 Middlewares can be added to a router using `Router.Use()`:
260
261         r := mux.NewRouter()
262         r.HandleFunc("/", handler)
263         r.Use(simpleMw)
264
265 A more complex authentication middleware, which maps session token to users, could be written as:
266
267         // Define our struct
268         type authenticationMiddleware struct {
269                 tokenUsers map[string]string
270         }
271
272         // Initialize it somewhere
273         func (amw *authenticationMiddleware) Populate() {
274                 amw.tokenUsers["00000000"] = "user0"
275                 amw.tokenUsers["aaaaaaaa"] = "userA"
276                 amw.tokenUsers["05f717e5"] = "randomUser"
277                 amw.tokenUsers["deadbeef"] = "user0"
278         }
279
280         // Middleware function, which will be called for each request
281         func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
282                 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
283                         token := r.Header.Get("X-Session-Token")
284
285                         if user, found := amw.tokenUsers[token]; found {
286                                 // We found the token in our map
287                                 log.Printf("Authenticated user %s\n", user)
288                                 next.ServeHTTP(w, r)
289                         } else {
290                                 http.Error(w, "Forbidden", http.StatusForbidden)
291                         }
292                 })
293         }
294
295         r := mux.NewRouter()
296         r.HandleFunc("/", handler)
297
298         amw := authenticationMiddleware{tokenUsers: make(map[string]string)}
299         amw.Populate()
300
301         r.Use(amw.Middleware)
302
303 Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to.
304
305 */
306 package mux