handler.go

36 lines
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
package router

import "net/http"

// Handler is the unit of composition in Congo: a function that wraps the next
// http.Handler and returns a replacement. Every middleware — a logger, an IP
// filter, a security guard, the application itself — is a Handler.
//
// Packages in other layers produce Handlers structurally: application.New and
// security.New already return func(http.Handler) http.Handler, which is
// assignable to Handler, so they plug into a Router without importing router.
// The type names the shape without forcing a dependency edge.
type Handler func(http.Handler) http.Handler

// Router is a statically-declared chain of Handlers. The first is outermost
// (closest to the wire); the last is terminal (typically the application). It
// is just a slice, so applications declare their stack as data:
//
//	var App = router.Router{
//	    router.WithLogger(),
//	    router.IpBlockList("203.0.113.0/24"),
//	    security.New(security.WithNonce(), security.WithHeaders()),
//	    application.New(views, application.WithController(controllers.Home())),
//	}
//	func main() { App.Listen() }
type Router []Handler

// build folds the chain into a single http.Handler and wraps it in domain-based
// proxy routing. The terminal floor is 404. The first Handler ends up outermost.
func (r Router) build() http.Handler {
	var h http.Handler = http.NotFoundHandler()
	for i := len(r) - 1; i >= 0; i-- {
		h = r[i](h)
	}
	return demux(h)
}