Skip to content

fharding1/gemux

Repository files navigation

Good Enough Multiplexer (gemux)

pkg.go.dev License: MIT

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.

Usage

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)
}

Features

Strict Path Based Routing (with wildcards)

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))

Strict Method Based Routing (with wildcards)

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

Context Path Parameters

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
    }

    // ...
}

Custom Error Handlers

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"})
})

Benchmarks

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

About

gemux is a good enough multiplexer

Resources

License

MIT, BSD-3-Clause licenses found

Licenses found

MIT
LICENSE.md
BSD-3-Clause
LICENSE_HTTPROUTER

Stars

Watchers

Forks

Packages

No packages published

Languages