cd /news/developer-tools/chi-like-syntactic-sugar-layer-on-to… · home topics developer-tools article
[ARTICLE · art-9754] src=gist.github.com ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Chi-like syntactic sugar layer on top of stdlib http.ServeMux

This code defines a lightweight router in Go that adds a Chi-like syntactic sugar layer on top of the standard library's `http.ServeMux`. It provides method-specific routing (GET, POST, PUT, DELETE, etc.), middleware chaining with `Use()`, and route grouping via `Group()`, while wrapping handlers with middleware in the correct order. The included example demonstrates creating a router with global middleware, grouped routes with additional middleware, and per-route middleware.

read2 min views21 publishedFeb 14, 2024

chi.go

  This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.

Learn more about bidirectional Unicode characters

Show hidden characters
// Chi-like syntactic sugar layer on top of stdlib http.ServeMux.

package main

import (
"net/http"

"slices"
)

type (
middleware func(http.Handler) http.Handler

router     struct {

	*http.ServeMux
		chain []middleware

	}

)

func NewRouter(mx ...middleware) *router {

	return &router{ServeMux: &http.ServeMux{}, chain: mx}

}

func (r *router) Use(mx ...middleware) {

	r.chain = append(r.chain, mx...)

}

func (r *router) Group(fn func(r *router)) {

	fn(&router{ServeMux: r.ServeMux, chain: slices.Clone(r.chain)})

}

func (r *router) Get(path string, fn http.HandlerFunc, mx ...middleware) {

	r.handle(http.MethodGet, path, fn, mx)

}

func (r *router) Post(path string, fn http.HandlerFunc, mx ...middleware) {
r.handle(http.MethodPost, path, fn, mx)
}

func (r *router) Put(path string, fn http.HandlerFunc, mx ...middleware) {

	r.handle(http.MethodPut, path, fn, mx)

}

func (r *router) Delete(path string, fn http.HandlerFunc, mx ...middleware) {
r.handle(http.MethodDelete, path, fn, mx)
}

func (r *router) Head(path string, fn http.HandlerFunc, mx ...middleware) {
r.handle(http.MethodHead, path, fn, mx)
}

func (r *router) Options(path string, fn http.HandlerFunc, mx ...middleware) {
r.handle(http.MethodOptions, path, fn, mx)
}

func (r *router) handle(method, path string, fn http.HandlerFunc, mx []middleware) {

	r.Handle(method+" "+path, r.wrap(fn, mx))

}

func (r *router) wrap(fn http.HandlerFunc, mx []middleware) (out http.Handler) {

	out, mx = http.Handler(fn), append(slices.Clone(r.chain), mx...)

	slices.Reverse(mx)

	for _, m := range mx {

		out = m(out)

	}
return

} example.go

  This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.

Learn more about bidirectional Unicode characters

Show hidden characters
package main

import (
"fmt"

"log"

"net/http"
)

func mid(i int) middleware {

	return func(next http.Handler) http.Handler {

		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

			fmt.Println("mid", i, "start")

			next.ServeHTTP(w, r)

			fmt.Println("mid", i, "done")

		})

	}

}

func someHandler(w http.ResponseWriter, r *http.Request) {

	fmt.Println("[the handler ran here]")
fmt.Fprintln(w, "Hello world of", r.URL.Path)
}

func main() {

	r := NewRouter(mid(0))

	r.Group(func(r *router) {

		r.Use(mid(1), mid(2))

		r.Get("/foo", someHandler)

	})

	r.Group(func(r *router) {

		r.Use(mid(3))

		r.Get("/bar", someHandler, mid(4))

		r.Get("/baz", someHandler, mid(5))

	})

	r.Post("/foobar", someHandler)

	log.Fatal(http.ListenAndServe(":3000", r))

}
── more in #developer-tools 4 stories · sorted by recency
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/chi-like-syntactic-s…] indexed:0 read:2min 2024-02-14 ·