A response has a status, headers and body. They form one contract. A JSON body with an HTML media type, a false success status or the wrong byte length is not fixed by a visually correct payload.
The response helper centralizes those mechanics. It encodes the value before committing the response, sets the JSON media type and nosniff header, and records the exact encoded length including one terminal newline.
Use encoding/json rather than concatenating user input into JSON text. The supplied encoding helper returns bytes or an error. A value such as a non-finite float cannot be represented by ordinary JSON, so the failure must occur before success headers are sent.
Call Header().Set before WriteHeader. A later attempt to change the status does not replace the first committed status.
package main
import ("fmt";"net/http/httptest")
func main(){
w:=httptest.NewRecorder();w.Header().Set("Content-Type","application/json; charset=utf-8");w.WriteHeader(201);_,_=w.Write([]byte("{}\n"));fmt.Println(w.Code,w.Header().Get("Content-Type"),w.Body.Len())
}HEAD carries the representation headers without writing its body. For the health response, the encoded object plus newline is 16 bytes; both GET and HEAD advertise that length, while HEAD writes zero body bytes.
After commitment, a network write can fail. Returning that error is useful, but writing a second JSON error response cannot safely undo a partially sent result. The final handler writes only encodable fixed structs/maps and ignores the returned error because there is no valid second response to send; a later instrumentation layer can observe failures without exposing private details.
The helper is deliberately small. It does not authenticate requests, set cross-origin policy or establish business correctness. Those belong to explicit application boundaries.
package main
import ("fmt";"encoding/json")
func main(){
b,_:=json.Marshal(map[string]string{"message":"<tag>"});var value map[string]string;_ =json.Unmarshal(b,&value);fmt.Println(value["message"])
}Complete the helper and test encoding failure, a writer failure, embedded data characters and HEAD. Keep byte length distinct from rune count.
Next we put state behind a repository interface so handlers can be tested without a database.