숏컷 코드
func createUser(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, 1<<20)
defer r.Body.Close()
var req CreateUserRequest
dec := json.NewDecoder(r.Body)
dec.DisallowUnknownFields()
if err := dec.Decode(&req); err != nil {
http.Error(w, "invalid JSON", http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(CreateUserResponse{ID: "u_123"})
}handler 흐름
request body는 제한하고 닫은 뒤 decode한다
JSON handler에서 가장 먼저 볼 것은 body 크기입니다. json.NewDecoder(r.Body)를 바로 호출하기 전에 http.MaxBytesReader로 크기 상한을 두면 큰 body로 인한 자원 낭비를 줄일 수 있습니다. handler가 body를 읽는 책임을 가지므로 defer r.Body.Close()도 함께 두는 편이 좋습니다.
DisallowUnknownFields는 엄격한 API 계약에 맞다
encoding/json decoder는 기본적으로 struct에 없는 JSON object key를 무시합니다. public API에서 오타를 빨리 잡고 싶거나, 클라이언트가 잘못된 field를 보내면 실패해야 하는 계약이라면 DisallowUnknownFields()를 켤 수 있습니다. 반대로 forward compatibility를 중요하게 보고 unknown field를 무시하는 정책이라면 기본 동작이 더 맞을 수 있습니다.
dec := json.NewDecoder(r.Body)
dec.DisallowUnknownFields()
if err := dec.Decode(&req); err != nil {
http.Error(w, "invalid JSON", http.StatusBadRequest)
return
}엄격함을 선택하면 클라이언트 배포 순서와 API versioning까지 같이 고려해야 합니다.
response는 header, status, body 순서로 쓴다
Go에서는 response body를 쓰기 전에 header와 status code를 먼저 정해야 합니다. json.NewEncoder(w).Encode(...)가 body를 쓰기 시작하면 status code는 기본 200 OK로 확정될 수 있습니다. 생성 성공이면 WriteHeader(http.StatusCreated)를 먼저 호출하고, 그 다음 JSON body를 씁니다.
선택 기준
| 상황 | 먼저 볼 것 |
|---|---|
| request body가 큰지 제한 | http.MaxBytesReader |
| JSON field 오타를 실패로 처리 | DisallowUnknownFields |
| backward/forward compatibility 우선 | unknown field 허용 |
| JSON 응답 | Content-Type: application/json |
| 생성 성공 | 201 Created 후 encode |
| decode 실패 | 400 Bad Request |
주의할 점
JSON response를 쓰기 시작한 뒤에는 status code를 바꾸기 어렵습니다. 응답 header와 status를 먼저 확정하고 그 다음 encoder를 호출하는 순서를 유지해야 합니다.
// 위험: Encode가 먼저 body를 쓰면 status가 200으로 확정될 수 있음
json.NewEncoder(w).Encode(resp)
w.WriteHeader(http.StatusCreated)status code가 중요한 handler에서는 WriteHeader를 body write보다 먼저 호출합니다.
참고 링크
2 sources