CodeBlanks Logo Icon CodeBlanks

Summary - net/http

Combine HandleFunc and JSON to write an API.

net/http summary

Client: an http.Client with a timeout, NewRequestWithContext, Do, checking StatusCode, defer resp.Body.Close(). Server: http.Handler/HandleFunc, Go 1.22 ServeMux patterns ("GET /path/{id}"), an http.Server with timeouts, JSON helpers, MaxBytesReader. Testing: httptest.NewRecorder and httptest.NewServer.

Graceful shutdown

To avoid cutting off in-flight requests when stopping the server, use Shutdown:

go func() {
    if err := srv.ListenAndServe(); err != http.ErrServerClosed {
        log.Fatal(err)
    }
}()
<-ctx.Done()  // SIGTERM
kapat, iptal := context.WithTimeout(context.Background(), 10*time.Second)
defer iptal()
srv.Shutdown(kapat)

Shutdown refuses new connections and waits until current requests finish (or time runs out).

Practice End to end

In a ServeMux, the "GET /saglik" route returns the JSON {"durum":"ok"}. Start it with httptest.NewServer(mux), request it with http.Get, decode the body into a map[string]string and print the durum value.

Starter code

main.go
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "net/http/httptest"
)

func main() {
    // buraya yaz
}

Sample solution

main.go
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "net/http/httptest"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("GET /saglik", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(map[string]string{"durum": "ok"})
    })
    srv := httptest.NewServer(mux)
    defer srv.Close()

    resp, err := http.Get(srv.URL + "/saglik")
    if err != nil {
        fmt.Println(err)
        return
    }
    defer resp.Body.Close()
    var m map[string]string
    json.NewDecoder(resp.Body).Decode(&m)
    fmt.Println(m["durum"])
}

Expected output

ok

Questions and answers

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

1 How do you test a handler without opening a real network port?

  • It isn't possible
  • httptest.NewRecorder + httptest.NewRequest Correct answer
  • http.ListenAndServe
  • curl

Explanation: The Recorder imitates a ResponseWriter; the handler is called directly and the code, headers and body are read from memory.

2 Shutdown error

Question
if err := srv.ListenAndServe(); err != http.____ {
    log.Fatal(err)
}
Answer
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
    log.Fatal(err)
}

Explanation: After Shutdown, ListenAndServe returns ErrServerClosed; this is expected.

3 Group summary

Term Meaning
http.Client{Timeout} Safe client
ServeMux Routing
httptest Network-free testing
srv.Shutdown Graceful shutdown

All lessons in Intermediate