읽는 데 6분
Go의 새 JSON API, import만 바꾸면 응답도 바뀔 수 있어요
서버 코드에서 import 한 줄을 바꿨는데, 앱이 받는 응답은 null에서 []로 바뀐다면 어떨까요. 컴파일러는 문제없다고 해도, 그 차이를 구분하던 클라이언트에는 다른 API가 된 셈이에요.
Go 팀이 11월 4일 소개한 encoding/json/v2가 딱 이런 변화예요. Go 1.27에서 정식 제공되는 새 JSON 표준 라이브러리인데, 기존 API와 사용법은 비슷하면서 기본 동작은 더 엄격해졌어요. 이 글은 실행 후기 대신 공식 발표와 이행 가이드, 패키지 문서를 대조해 바뀌는 데이터에 초점을 맞췄어요.
기본 동작이 달라지는 곳
JSON은 서버와 앱이 주고받는 데이터 형식이에요. Go의 Marshal은 Go 값을 JSON으로 바꾸고, Unmarshal은 반대로 JSON을 Go 값에 담아요. 새 버전에서도 이 함수 이름은 같지만, 같은 입력의 처리 결과까지 같지는 않아요.
아래는 별도 호환 옵션을 주지 않았을 때의 차이예요.
| 상황 | 기존 encoding/json | 새 encoding/json/v2 |
|---|---|---|
| nil 슬라이스를 JSON으로 변환 | null |
빈 배열 [] |
| nil 맵을 JSON으로 변환 | null |
빈 객체 {} |
| 객체에 같은 이름의 키가 두 번 등장 | 허용 | 오류 |
| JSON 키를 Go 구조체 필드에 대응 | 대소문자를 구분하지 않는 매칭 허용 | 기본적으로 대소문자 구분 |
슬라이스는 목록을 담는 Go 자료형이고, nil은 값이 아직 없는 상태를 나타내요. 공식 가이드의 예제에서는 별명을 넣지 않은 반려동물의 Nicknames가 기존 패키지에서는 null, v2에서는 []로 나와요. 새로 만드는 API라면 빈 목록이 더 자연스러울 수 있죠. 하지만 이미 null을 특별한 의미로 쓰는 클라이언트가 있다면 변경 전에 확인해야 해요.
중복 키를 거부하는 건 파서마다 같은 데이터를 다르게 읽을 여지를 줄이려는 선택이에요. 예를 들어 인증을 확인하는 서비스와 실제 작업을 수행하는 서비스가 같은 요청을 서로 다른 사용자로 해석한다면 위험하겠죠. 공식 문서는 이런 시스템 사이의 해석 차이를 보안 문제로 설명해요.
다만 v2가 모든 잘못된 필드를 자동으로 오류 처리하는 건 아니에요. 구조체에 대응하지 않는 알 수 없는 필드는 기본적으로 무시해요. 대소문자가 맞지 않아 값이 안 들어가는 경우와 요청 전체가 거부되는 경우는 구분해야 해요. 모르는 필드도 거부하려면 RejectUnknownMembers 옵션이 필요해요.
기존 응답을 지키며 옮기는 방법
당장 옮길 의무는 없어요. Go 팀은 기존 encoding/json도 호환성 약속에 따라 계속 지원한다고 밝혔어요.
옮기고 싶다면 새 API와 새 기본 동작을 한꺼번에 도입할 필요는 없어요. 공식 가이드는 먼저 v2를 쓰면서 기존 동작을 선택하는 방법을 보여 줘요.
import (
jsonv1 "encoding/json"
"encoding/json/v2"
)
// v2 API를 사용하되 v1 호환 동작으로 변환해요.
b, err := json.Marshal(value, jsonv1.DefaultOptionsV1())
이건 완성된 프로그램이 아니라 호출 형태를 보여 주는 예예요. value는 변환할 Go 값이고, b와 err로 결과와 오류를 받아요. 그다음 필요한 옵션만 하나씩 바꾸며 응답을 비교할 수 있어요.
운영 중에 실제 데이터의 차이를 찾고 싶다면 공식 가이드가 소개하는 별도 패키지 jsonsplit도 있어요. 같은 값을 v1과 v2로 각각 변환해 차이를 기록하면서, 호출자에게는 계속 v1 결과를 돌려주는 모드가 있어요. 새 결과가 어디서 달라지는지 먼저 관찰하는 방식이죠.
대신 양쪽 변환을 실행하므로 비용이 늘어요. 가이드는 일부 호출만 무작위로 비교하는 설정도 안내해요. 결과가 다르다는 로그가 곧 장애를 뜻하는 것도 아니에요. 실제 클라이언트가 그 차이에 의존하는지 판단할 단서예요.
API를 운영한다면 이 순서가 출발점이 될 수 있어요.
- 기존 응답 예제와 테스트에서
null과 빈 목록의 의미를 확인해요. - 중복 키나 대소문자가 다른 요청을 어떻게 처리하는지 비교해요.
- 필요한 호환 옵션을 남긴 뒤, 바꿔도 되는 동작부터 전환해요.
함수 호출을 고치는 일보다, 내 서비스가 어떤 JSON을 약속했는지 확인하는 일이 이행의 중심이에요.
확인한 범위
- 기준일: 2026-11-05.
- 읽은 것: Go 공식 발표, 공식 이행 가이드, json/v2 패키지의 기본 동작과 보안 설명. 발표의 변경점을 별도 패키지 문서 및 가이드 예제와 대조했어요.
- 읽지 못한 것: 전체 구현 코드와 모든 타입별 이행 예외.
- 직접 해보지 못한 것: Go 1.27 실행, jsonsplit 적용, 실제 서비스의 성능과 클라이언트 호환성 시험. 위 결과 비교는 공식 문서에 제시된 동작이에요.
출처


기본 동작의 세부 조건은 encoding/json/v2 패키지 문서에서 확인할 수 있어요.

