negroniの実装をちゃんと理解できていなかったので自分で書き直してみる
以前、ミドルウェアをうまく扱うパッケージとしてnegroniを紹介したが、改めてコードを読むとちゃんと理解できていなかったので自分で書き直してみる。車輪の再発明。GitHubに上げるまでもないのでここに残す。
GitHub - urfave/negroni: Idiomatic HTTP Middleware for Golang
package chain import ( "net/http" ) // Handler is an interface. type Handler interface { ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) } // HandlerFunc is an adapter to allow the use of ordinary functions as HTTP handlers. type HandlerFunc func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) // ServeHTTP simply calls f(w, r, next). func (f HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { f(w, r, next) } // Middleware is a stack of middlwares. type Middleware struct { handler Handler next *Middleware } // ServeHTTP calls ServeHTTP of next middleware. func (m Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { m.handler.ServeHTTP(w, r, m.next.ServeHTTP) } // Wrap converts http.Handler into chain.Handler func Wrap(h http.Handler) Handler { return HandlerFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { h.ServeHTTP(w, r) next(w, r) }) } // New is the constructor of Middlewre func New(handlers ...Handler) Middleware { return *build(handlers) } func build(handlers []Handler) *Middleware { var next *Middleware if len(handlers) == 0 { return voidMiddleware() } else if len(handlers) > 1 { next = build(handlers[1:]) } else { next = voidMiddleware() } return &Middleware{handlers[0], next} } func voidMiddleware() *Middleware { return &Middleware{ handler: HandlerFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {}), next: &Middleware{}, } }
メモ。
使い方は以下の通り。
package main import ( "./chain" "net/http" ) func hello1(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { w.Write([]byte("Hello1\n")) next(w, r) } func hello2(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { w.Write([]byte("Hello2\n")) next(w, r) } func hello3(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { w.Write([]byte("Hello3\n")) next(w, r) } // MyHandler is a sample handler. type MyHandler struct{} // ServeHTTP greet to world. func (mh MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello, world!\n")) } func main() { n := chain.New( chain.HandlerFunc(hello1), chain.HandlerFunc(hello2), chain.HandlerFunc(hello3), chain.Wrap(MyHandler{}), ) http.ListenAndServe(":8888", n) }