Skip to content

API Reference

Response Writer

Reference for zinc.WrapResponseWriter, which lets middleware observe the status and size of a response.

Middleware sometimes needs to know what a handler sent: the status for metrics, or the byte count for logs. zinc.WrapResponseWriter wraps the current writer and records both.

func metrics(c *zinc.Context) error {
base := c.Writer()
rw := zinc.WrapResponseWriter(base)
c.SetWriter(rw)
defer c.SetWriter(base) // always restore the original writer
start := time.Now()
err := c.Next()
requestDuration.
WithLabelValues(c.FullPath(), strconv.Itoa(rw.Status())).
Observe(time.Since(start).Seconds())
return err
}
type ResponseWriter interface {
http.ResponseWriter
Status() int // 200 until another status is written
BytesWritten() int // body bytes written so far
Written() bool // whether headers or body have been sent
}

When a handler returns an error, the error handler writes the response after your middleware has already returned, so rw.Status() still reports 200. To measure the final response, send the error to the error handler first:

err := c.Next()
if err != nil {
c.Error(err) // writes the error response through rw now
}
record(rw.Status(), rw.BytesWritten())
return err

The Custom Middleware recipe uses this pattern in a complete program.

The wrapper keeps the optional interfaces of the writer it wraps: http.Flusher, http.Hijacker, io.ReaderFrom, and http.Pusher. It also implements Unwrap() http.ResponseWriter, so http.ResponseController reaches the original writer.