Crash Courses · PhD
HTTP Server with net/http
Serve HTTP requests, handle routes, and write JSON responses
45 min read+195 XP on completionCert: Go Crash Course
Tap any word in the text below to start reading from there.
HTTP Server with net/http
The Simplest Server
package main
import (
"fmt"
"net/http"
)
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, Web!")
}
func main() {
http.HandleFunc("/", hello)
http.ListenAndServe(":8080", nil)
}Visit http://localhost:8080 — you should see "Hello, Web!".
Returning JSON
package main
import (
"encoding/json"
"net/http"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
func getUser(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
user := User{ID: 1, Name: "Jordan"}
json.NewEncoder(w).Encode(user)
}
func main() {
http.HandleFunc("/user", getUser)
http.ListenAndServe(":8080", nil)
}Status Codes
func notFound(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Not Found", http.StatusNotFound) // 404
}Custom ServeMux
Using the global DefaultServeMux is fine for simple programs, but in production you want your own:
mux := http.NewServeMux()
mux.HandleFunc("/", homeHandler)
mux.HandleFunc("/api/users", usersHandler)
server := &http.Server{
Addr: ":8080",
Handler: mux,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
server.ListenAndServe()Setting timeouts is critical — the default http.Server has no timeouts.
Reading Request Body
func createUser(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
return
}
var user User
err := json.NewDecoder(r.Body).Decode(&user)
if err != nil {
http.Error(w, "Bad Request", http.StatusBadRequest)
return
}
// process user...
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(user)
}Reading URL Query Parameters
func search(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query().Get("q")
fmt.Fprintf(w, "Searching for: %s", query)
}
// GET /search?q=golangPath Variables (Go 1.22+)
Go 1.22 added pattern matching to the standard mux:
mux.HandleFunc("GET /users/{id}", func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
fmt.Fprintf(w, "User ID: %s", id)
})Reading progress
0% read
In this module
http.HandlerFunc
http.ResponseWriter
*http.Request
http.ServeMux
0%