CodeBlanks Logo Icon CodeBlanks

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.

Practice Struct handler

Write the SayacHandler above. Send two requests to the same handler with httptest.NewRecorder and print the body of the second response.

Starter code

main.go
package main

import (
    "fmt"
    "net/http"
    "net/http/httptest"
    "sync"
)

func main() {
    // buraya yaz
}

Sample solution

main.go
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())
}

Expected output

ziyaret: 2

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 What is the correct order for setting a response header?

  • Header().Set → WriteHeader → Write Correct answer
  • Write → Header().Set
  • WriteHeader → Header().Set → Write
  • The order doesn't matter

Explanation: WriteHeader (or the first Write) sends the headers; Header().Set changes made after that have no effect.

2 Interface method

Question
func (h *Api) ____(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("ok"))
}
Answer
func (h *Api) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("ok"))
}

Explanation: Any type with a ServeHTTP method satisfies the http.Handler interface.

3 Request field

Term Meaning
r.Method GET, POST...
r.URL.Path Path
r.Header Headers
r.Context() Cancellation and values

All lessons in Intermediate