Important notes about subtle things related to the needs of the API

Matt Holt 2015-06-06 17:38:45 -06:00
parent 8c9a00ea73
commit f9e4d58dd5

@ -18,19 +18,25 @@ type MyHandler struct {
} }
``` ```
It must also implement the middleware.Handler interface. We do this by adding a method called ServeHTTP. Right now, let's just pass the request to the next Handler in the chain: It must also implement the middleware.Handler interface. We do this by adding a method called ServeHTTP and two one-liners called GetNext and SetNext. Right now, let's just pass the request to the next Handler in the chain:
```go ```go
func (h MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
return h.Next.ServeHTTP(w, r) return h.Next.ServeHTTP(w, r)
} }
// These allow the middleware stack to be traversed like a singly-linked list
func (h *MyHandler) GetNext() middleware.Handler { return h.Next }
func (h *MyHandler) SetNext(next middleware.Handler) { h.Next = next }
``` ```
That's all there is to it. Put your middleware logic in the ServeHTTP method, and add any properties that your middleware may need to access to the struct type you defined your middleware to be. That's all there is to it. Put your middleware logic in the ServeHTTP method, and add any properties that your middleware may need to access to the struct type you defined your middleware to be.
Be careful to use pointer receivers.
## Return Values and Writing Responses ## Return Values and Writing Responses
Oh yes, those pesky return values. You read the documentation so you already know what they mean. But what does that imply for the behavior of your middleware? Oh yes, those pesky return values on `ServeHTTP()`. You read the documentation so you already know what they mean. But what does that imply for the behavior of your middleware?
Some handlers are endpoints: they create a response and write it along with the status code to the client. Effectively, this terminates the chain. You wouldn't want to write a document out to the client and then tell the next handler in the chain, "Okay it's all yours!" In this situation, you would *not* call Next(). Some handlers are endpoints: they create a response and write it along with the status code to the client. Effectively, this terminates the chain. You wouldn't want to write a document out to the client and then tell the next handler in the chain, "Okay it's all yours!" In this situation, you would *not* call Next().
@ -53,18 +59,31 @@ func MyMiddleware(c *Controller) (middleware.Middleware, error) {
// do parsing // do parsing
} }
// set up your middleware type // Don't create your middleware struct in this function!
myType := mymiddleware.MyType{/* ... */}
return func(next middleware.Handler) middleware.Handler { return func(next middleware.Handler) middleware.Handler {
// chain in the next handler and return it // This function will be called every time the server
myType.Next = next // is started. Create and return your middleware
return myType // struct here to ensure it gets the latest config.
// Return a POINTER - very important!
return &mymiddleware.MyType{
Next: next,
// ...
}
}, nil }, nil
} }
``` ```
The Controller gives you access to the server.Config and some really helpful parsing utilities to easily get values out of the Caddyfile. The Controller gives you access to the `*server.Config` and some really helpful parsing utilities to easily get values out of the Caddyfile.
Your middleware type should be able to support multiple invocations, usually called "rules" - for example, a Caddyfile like this:
```
rewrite /foo /bar
rewrite /bar /baz
```
creates just 1 struct but that struct holds 2 rules, for example, in a field like this: `Rules []Rule`.
Once that's all set up, register your middleware in [config/directives.go](https://github.com/mholt/caddy/blob/master/config/directives.go). The ordering is very important, so be sure to get it right! Once that's all set up, register your middleware in [config/directives.go](https://github.com/mholt/caddy/blob/master/config/directives.go). The ordering is very important, so be sure to get it right!