Request Parsing
Fast recall
Quick revision
Core answer
Whether you understand Request Parsing beyond memorized syntax.
Giving a definition without explaining a practical trade-off.
Connect the concept to a small production example and state its complexity or failure mode.
Interview-ready guide
Interview answer
The three request surfaces, all executed:
Query params:
// GET /search?q=go&page=2
q := r.URL.Query().Get("q") // "go"
page := r.URL.Query().Get("page") // "2" (string — convert with strconv.Atoi)Headers:
ctype := r.Header.Get("Content-Type")
auth := r.Header.Get("Authorization")Body — JSON (the API path):
var req struct {
Name string `json:"name"`
Age int `json:"age"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// POST {"name":"Bo","age":25} → req.Name "Bo", req.Age 25 — verifiedBody — form data:
r.ParseForm() // or r.ParseMultipartForm(32 << 20)
name := r.FormValue("name")The conventions: always check the decode error (a malformed JSON is a 400, not a 500); check the Content-Type when it matters; r.Body is a stream — read it once (json.Decoder handles it; manual reads need io.ReadAll and close).
The method:
switch r.Method {
case http.MethodGet: // "GET"
case http.MethodPost: // "POST"
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}Executed: GET /api → "GET"; POST → "POST"; other → 405.
Request Parsing
Direct Answer
Query: r.URL.Query().Get("q"). Headers: r.Header.Get("Content-Type"). Body: json.NewDecoder(r.Body).Decode(&req) for JSON, r.ParseForm() for form data. Method: r.Method.
Deep Dive & Architecture
The query params' mechanics: r.URL.Query() parses the RawQuery string (the part after ?) into url.Values (a map[string][]string — each key can have multiple values). Get returns the FIRST value; the full slice is Values["q"] for multi-value params (?tag=a&tag=b).
The body-stream subtlety: r.Body is an io.ReadCloser — single-pass. json.NewDecoder reads it incrementally (streaming — can decode a sequence of JSON values); io.ReadAll buffers the whole thing (fine for small bodies; use http.MaxBytesReader for a limit — an unbounded ReadAll on a malicious upload is OOM).
The 400-vs-500 discipline: malformed input is the CLIENT's fault (400 Bad Request); your code's failure is yours (500). Decode errors are 400s — always. The common bug: treating a JSON decode error as an internal failure, masking what's actually a client bug and misdirecting debugging.
The 1.22+ context integration: r.Context() is the request's cancellation — client disconnects, the context cancels, and handlers that check ctx (via r.Context().Done()) stop early. The pattern: r.Context() into your downstream calls (DB queries with context, HTTP calls with context) so a client disconnect doesn't waste a full compute cycle — the goroutine-per-request model's graceful exit.
Common Mistakes & Pitfalls
Giving a definition without explaining a practical trade-off.
Check your understanding
Answer these without looking back at the article.
- When would you use Request Parsing in a real project?
- How would you compare Request Parsing with an alternative?
- What is a common mistake when using Request Parsing?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.