Open this lesson in your favourite AI. It'll walk you through the why, explain the demo, and quiz you on the try-it list.
HTTP is five things: a method (GET, POST, PUT, DELETE, PATCH), a path (/users/42), a version (HTTP/1.1 or HTTP/2), a headers block, and a body. Status codes group into five bands: 1xx informational, 2xx success, 3xx redirect, 4xx client error, 5xx server error. You won't remember every code, but you'll use 200, 201, 204, 301, 302, 400, 401, 403, 404, 409, 422, and 500 constantly. curl -v shows you all of it.
HTTP's five-group status code system encodes every outcome a server can communicate: 2xx succeeded, 4xx the client did something wrong, 5xx the server did. A GET retrieves, a POST creates or triggers — and curl -v shows you the raw status line, headers, and body the same way every HTTP client in the world sees them. Reading that output fluently is the single fastest debugging skill you can build.
curl -v http://localhost:8080/users/42. Read every line of output.curl -v http://localhost:8080/users/99. Note the < HTTP/1.1 404 Not Found line. That's the status code.curl -v -X POST http://localhost:8080/users -d '{"name":"Ada"}' -H 'content-type: application/json'. Note the < HTTP/1.1 201 Created.-H 'Accept: application/xml' on the GET. Servers can handle content negotiation, but most won't. What does yours do?Use these three in order. Each builds on the one before.
Walk me through the five status code bands (1xx–5xx) with two examples from each. When should a server return 400 vs 422? When 404 vs 410?
`curl -v` shows both the request it sent and the response it received. Walk me through each `>` line (request) and each `<` line (response) in a typical GET — what is each one for, and how does the server use them?
Your team is debating whether a failed password login should return 401 Unauthorized, 403 Forbidden, or 404 Not Found (to avoid leaking which emails exist). What are the tradeoffs, and what's the current convention in serious security-minded APIs?
package main
import (
"encoding/json"
"io"
"net/http"
)
func main() {
mux := http.NewServeMux()
// GET /users/42 -> 200 with user
mux.HandleFunc("GET /users/{id}", func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
if id != "42" {
http.Error(w, "user not found", http.StatusNotFound) // 404
return
}
json.NewEncoder(w).Encode(map[string]string{"id": id, "name": "Ada"})
})
// POST /users -> 201 created
mux.HandleFunc("POST /users", func(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
w.WriteHeader(http.StatusCreated) // 201
w.Write(body)
})
http.ListenAndServe(":8080", mux)
}go run main.go