숏컷 코드
type User struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email,omitempty"`
}Go JSON 처리는 exported field, struct tag, zero value를 같이 읽어야 합니다.
문법
exported field만 기본으로 JSON 대상이 된다
type User struct {
ID string
name string
}ID는 대문자로 시작하므로 exported field이고, encoding/json이 기본으로 읽을 수 있습니다. name은 unexported field라 기본 JSON 변환 대상이 아닙니다.
struct tag로 JSON 이름을 정한다
type User struct {
ID string `json:"id"`
Name string `json:"name"`
}Go 필드 이름은 ID, Name처럼 쓰고, JSON 표면은 id, name처럼 맞출 수 있습니다.
필드를 빼고 싶으면 -를 씁니다.
type User struct {
PasswordHash string `json:"-"`
}omitempty는 zero value일 때 생략한다
type User struct {
Email string `json:"email,omitempty"`
Age int `json:"age,omitempty"`
}omitempty는 빈 문자열, 0, false, nil slice/map/pointer 같은 empty value를 출력에서 생략합니다. "필드가 없었다"와 "0이었다"를 구분해야 하는 API에서는 포인터나 별도 타입을 검토해야 합니다.
변환 흐름
Marshal은 Go 값을 JSON 바이트로 바꾼다
data, err := json.Marshal(user)
if err != nil {
return err
}Unmarshal은 포인터를 받는다
var user User
if err := json.Unmarshal(data, &user); err != nil {
return err
}Unmarshal은 대상 값을 채워야 하므로 포인터가 필요합니다.
외부 입력은 구조 검증을 같이 본다
json.Unmarshal은 타입 변환은 해 주지만, 비즈니스 규칙을 검증하지는 않습니다.
if user.ID == "" {
return errors.New("missing id")
}필수 필드, 값 범위, enum 같은 규칙은 별도 검증으로 둬야 합니다.
선택 기준
| 상황 | 먼저 떠올릴 선택 |
|---|---|
| JSON 필드 이름 지정 | struct tag |
| 출력에서 빈 값 생략 | omitempty |
| 민감 필드 제외 | json:"-" |
| JSON 생성 | json.Marshal |
| JSON 파싱 | json.Unmarshal(data, &target) |
| 누락과 zero value 구분 | pointer 또는 별도 검증 |
주의할 점
Go JSON에서 가장 자주 생기는 오해는 omitempty가 검증이라는 착각입니다. omitempty는 출력 생략 규칙일 뿐이고, 입력 JSON의 필수 필드나 값 범위는 별도로 확인해야 합니다. 또한 unexported field는 struct tag를 붙여도 기본 JSON 변환 대상이 아닙니다.
참고 링크
2 sources