fmt, io, os, bufio, encoding/json, net/http, time, slog, regexp, flag, embed.
net/http Client & Server
Go's HTTP server is in the standard library and is genuinely production-ready —
it's what runs huge chunks of the internet, by way of services that just import
net/http.
A tiny HTTP server
In a real server:
log.Fatal(http.ListenAndServe(":8080", nil))
http.HandleFunc(pattern, fn)registers a function as a handler forpattern.- A handler is any value with
ServeHTTP(w http.ResponseWriter, r *http.Request). http.ResponseWriteris anio.Writerplus headers and status code.*http.Requesthas the URL, method, headers, query params, and body.
A JSON endpoint
http.HandleFunc("/api/user", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{
"name": "Ada",
})
})
Routing in Go 1.22+
Since Go 1.22, the built-in mux understands methods and path values:
mux := http.NewServeMux()
mux.HandleFunc("GET /users/{id}", func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
fmt.Fprintln(w, "user", id)
})
http.ListenAndServe(":8080", mux)
That's enough for many services — no third-party router required.
The HTTP client
The same package gives you an HTTP client.
resp, err := http.Get("https://api.github.com/zen")
if err != nil { return err }
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
For more control (timeouts, custom transports), build your own &http.Client{}
and use client.Do(req). Always set a timeout on production clients — the
default has none.
client := &http.Client{Timeout: 5 * time.Second}
resp, err := client.Get(url)
Middleware
A middleware is just a function that takes a handler and returns a handler. It's the standard way to add logging, auth, recovery, request IDs, etc.:
func withLogging(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))
})
}
http.ListenAndServe(":8080", withLogging(mux))
Compose as many layers as you need. The first wrapper added is the outermost ("onion model").