Package router provides a lightning fast HTTP router.
- Extreme performance: sub-microsecond routing in most cases
- Full compatibility with the http.Handler interface
- Generic: no magic methods, bring your own handlers
- Path parameters, wildcards and smart prioritized routes
- Zero memory allocation during serving (unless for parameters)
- Respecting the principle of least surprise
- Tested and used in production
-
Get package:
go get -u github.com/gowww/router
-
Import it in your code:
import "github.com/gowww/router"
-
Make a new router:
rt := router.New()
-
Make a route:
rt.Handle("GET", "/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "Hello") }))
Remember that HTTP methods are case-sensitive and uppercase by convention (RFC 7231 4.1).
So you can directly use shortcuts for standard HTTP methods: Router.Get, Router.Post, Router.Put, Router.Patch and Router.Delete. -
Give the router to the server:
http.ListenAndServe(":8080", rt)
A named parameter begins with : and matches any value until the next / in path.
To retreive it's value (stored in request's context), ask Parameter.
It will return the value as a string (empty if the parameter doesn't exist).
Example, with a parameter :id:
rt.Get("/users/:id", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
id := router.Parameter(r, "id")
fmt.Fprintf(w, "Page of user #%s", id)
}))No surprise, a parameter can be used on the same level as a static route, without conflict:
rt.Get("/users/all", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "All users page")
}))
rt.Get("/users/:id", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
id := router.Parameter(r, "id")
fmt.Fprintf(w, "Page of user #%s", id)
}))A trailing slash in a route path is significant.
It behaves like a wildcard by matching the beginning of the request's path and keeping the rest as a parameter value, under *:
rt.Get("/files/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
filepath := router.Parameter(r, "*")
fmt.Fprintf(w, "Get file %s", filepath)
}))No surprise, deeper route paths with the same prefix as the wildcard will take precedence, without conflict:
// Will match:
// /files/one
// /files/two
// ...
rt.Get("/files/:name", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
name := router.Parameter(r, "name")
fmt.Fprintf(w, "Get root file #%s", name)
}))
// Will match:
// /files/one/...
// /files/two/...
// ...
rt.Get("/files/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
filepath := router.Parameter(r, "*")
fmt.Fprintf(w, "Get file %s", filepath)
}))
// Will match:
// /files/movies/one
// /files/movies/two
// ...
rt.Get("/files/movies/:name", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
name := router.Parameter(r, "name")
fmt.Fprintf(w, "Get movie #%s", name)
}))Note that a trailing slash in a request path is always trimmed and the client redirected (good for SEO).
For example, a request for /files/ will be redirected to /files and will never match a /files/ route.
In other words, /files and /files/ are two different routes.
For serving static files, like for other routes, just bring your own handler.
Exemple, with the standard net/http.FileServer:
rt.Get("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))When a request cannot be matched with a route, a 404 error with an empty body is send by default.
But you can set your own "not found" handler (and send an HTML page, for example):
rt.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.NotFound(w, r)
})Note that is this case, it's up to you to set the correct status code (normally 404) for the response.