gemux is a good enough multiplexer
MIT License
gemux
is the good enough multiplexer. It aims to provide functionality that is good enough for the majority of HTTP services,
with a focus on a small and easy to test codebase, fair performance, and no dependencies outside the standard library.
package main
func main() {
mux := new(gemux.ServeMux)
mux.Handle("/", http.MethodGet, http.HandlerFunc(healthHandler))
mux.Handle("/posts", http.MethodGet, http.HandlerFunc(getPostsHandler))
mux.Handle("/posts", http.MethodPost, http.HandlerFunc(createPostHandler))
mux.Handle("/posts/*", http.MethodDelete, http.HandlerFunc(deletePostHandler))
mux.Handle("/posts/*/comments", http.MethodPost, http.HandlerFunc(createCommentHandler))
mux.Handle("/posts/*/comments", http.MethodGet, http.HandlerFunc(getCommentsHandler))
mux.Handle("/posts/*/comments/*", http.MethodDelete, http.HandlerFunc(deleteCommentHandler))
http.ListenAndServe(":8080", mux)
}
Route strictly based on paths, but allow wildcards for path parameters such as a resource ID.
mux.Handle("/users", http.MethodPost, http.HandlerFunc(getUsersHandler))
mux.Handle("/posts", http.MethodPost, http.HandlerFunc(createPostHandler))
mux.Handle("/posts/*", http.MethodGet, http.HandlerFunc(getPostHandler))
Route based on methods, and allow wildcard methods if you need to write your own method multiplexer, or want to match on any method.
mux.Handle("/users", http.MethodGet, http.HandlerFunc(createPostHandler)) // implement your own method muxer
mux.Handle("/posts", "*", http.HandlerFunc(createPostHandler)) // implement your own method muxer
Extract path wildcard values via the request context.
func getPostHandler(w http.ResponseWriter, r *http.Request) {
rawPostID := gemux.PathParameter(r.Context(), 0)
postID, err := strconv.ParseInt(rawPostID, 10, 64)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// ...
}
Create custom error handlers for when a route or method isn't found.
mux := new(gemux.ServeMux)
mux.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
json.NewEncoder(w).Encode(map[string]string{"error": "not found"})
})
mux.MethodNotAllowedHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusMethodNotAllowed)
json.NewEncoder(w).Encode(map[string]string{"error": "method not allowed"})
})
Performed on a Dell XPS 13 with an Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz. gemux
is fast enough
that it's performance impact is negligible for most HTTP services.
goos: linux
goarch: amd64
pkg: github.com/fharding1/gemux
BenchmarkServeHTTP/one_static_path-8 7071818 159 ns/op
BenchmarkServeHTTP/one_wildcard_path-8 2432485 516 ns/op
BenchmarkServeHTTP/one_wildcard_path_and_method-8 2541954 453 ns/op
BenchmarkServeHTTP/short_path_with_many_routes-8 6360070 187 ns/op
BenchmarkServeHTTP/very_deep_static_path-8 1856644 644 ns/op
BenchmarkServeHTTP/very_deep_wildcard_path-8 499780 2262 ns/op
BenchmarkHandle/one_static_path-8 6987087 170 ns/op
BenchmarkHandle/one_wildcard_path-8 8136362 151 ns/op
BenchmarkHandle/one_wildcard_path_and_method-8 8723088 139 ns/op
BenchmarkHandle/short_path_with_many_routes-8 191238 6234 ns/op
BenchmarkHandle/very_deep_static_path-8 1626010 694 ns/op
BenchmarkHandle/very_deep_wildcard_path-8 2015136 616 ns/op
PASS
ok github.com/fharding1/gemux 18.140s