net/http is a full HTTP client and server, no framework required.
Examples
Bare ListenAndServe sets no timeouts. Configure a *Server.
mux := http.NewServeMux()
mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte("{\"status\":\"ok\"}"))
})
server := &http.Server{
Addr: ":8080",
Handler: mux,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}
log.Fatal(server.ListenAndServe())Output
$ curl localhost:8080/health
{"status":"ok"}Go 1.22+ patterns include method and path wildcards.
mux := http.NewServeMux()
mux.HandleFunc("GET /users/{id}", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "get user %s", r.PathValue("id"))
})
mux.HandleFunc("DELETE /users/{id}", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
})
http.ListenAndServe(":8080", mux)Output
$ curl localhost:8080/users/42
get user 42No WebSocket parser in stdlib, Hijacker hands you the raw connection.
func wsHandler(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Upgrade") != "websocket" {
http.Error(w, "expected websocket upgrade", http.StatusBadRequest)
return
}
hj, ok := w.(http.Hijacker)
if !ok {
http.Error(w, "server doesn't support hijacking", http.StatusInternalServerError)
return
}
conn, bufrw, err := hj.Hijack()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer conn.Close()
bufrw.WriteString("HTTP/1.1 101 Switching Protocols\r\n")
bufrw.WriteString("Upgrade: websocket\r\n")
bufrw.WriteString("Connection: Upgrade\r\n\r\n")
bufrw.Flush()
}Output
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade| Function | Description |
|---|---|
NewServeMux() *ServeMux mux := http.NewServeMux() | Empty router. Register routes on the returned value. |
(*ServeMux) HandleFunc(pattern string, fn func(ResponseWriter, *Request)) mux.HandleFunc("GET /health", h) | Go 1.22+ patterns can include a method: "GET /path". |
ListenAndServe(addr string, handler Handler) error log.Fatal(http.ListenAndServe(":8080", mux)) | Blocks. Error only on shutdown. |
(*Server) ListenAndServe() error log.Fatal(server.ListenAndServe()) | Same, on a *Server you configured yourself. |
Error(w ResponseWriter, msg string, code int) http.Error(w, "bad request", 400) | Writes status + message directly to w. |
Get(url string) (*Response, error) resp, err := http.Get(u) | defer resp.Body.Close() once err is nil. |
NewRequest(method, url string, body io.Reader) (*Request, error) req, err := http.NewRequest("GET", u, nil) | For use with a custom *Client. |
Handler interface { ServeHTTP(ResponseWriter, *Request) } func (h) ServeHTTP(w, r) | Implement this to be usable as a Handler. |
Hijacker interface { Hijack() (net.Conn, *bufio.ReadWriter, error) } conn, bufrw, err := hj.Hijack() | Type-assert w to get the raw connection. |