Go
http.Handler
Learn the Handler interface and ServeHTTP.
http.Handler
At the heart of the server side is a single-method interface:
type Handler interface {
ServeHTTP(w http.ResponseWriter, r *http.Request)
}
r carries everything about the request (method, path, headers, body, context); w writes the status code, headers and body. Any type with a ServeHTTP method is a handler, so handlers that hold state can be written as structs.
A stateful handler
A struct handler that takes its dependencies (database, logger, settings) helps avoid global variables:
type SayacHandler struct {
mu sync.Mutex
n int
}
func (h *SayacHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.mu.Lock()
h.n++
n := h.n
h.mu.Unlock()
fmt.Fprintf(w, "ziyaret: %d", n)
}
Because the server handles every request in its own goroutine, shared state is protected by a lock.
Exercise Struct handler
Write the SayacHandler above. Send two requests to the same handler with httptest.NewRecorder and print the body of the second response.
Show example solution
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"sync"
)
type SayacHandler struct {
mu sync.Mutex
n int
}
func (h *SayacHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.mu.Lock()
h.n++
n := h.n
h.mu.Unlock()
fmt.Fprintf(w, "ziyaret: %d", n)
}
func main() {
h := &SayacHandler{}
h.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", "/", nil))
rec := httptest.NewRecorder()
h.ServeHTTP(rec, httptest.NewRequest("GET", "/", nil))
fmt.Println(rec.Body.String())
}
Test yourself
-
What is the correct order for setting a response header?
- Header().Set → WriteHeader → Write
- Write → Header().Set
- WriteHeader → Header().Set → Write
- The order doesn't matter
Show answer
Header().Set → WriteHeader → Write — WriteHeader (or the first Write) sends the headers; Header().Set changes made after that have no effect.
-
Interface method
func (h *Api) ____(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("ok"))
}
Show answer
func (h *Api) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("ok"))
}
-
Request field
- r.Method
- GET, POST...
- r.URL.Path
- Path
- r.Header
- Headers
- r.Context()
- Cancellation and values
Next lesson: http.HandleFunc