JSON 데이터 교환 형식과 검증 파이프라인
JSON의 데이터 모델과 직렬화·역직렬화 과정, 스키마 검증, API·이벤트·설정 관리에서의 운영 원칙을 정리한다.
2026-08-14 · 최초 발행 2025-10-14
JSON이 데이터 인터페이스가 되는 방식
JSON(JavaScript Object Notation)은 웹과 분산 시스템에서 표준 데이터 교환 형식으로 자리 잡았다. 텍스트 기반이라 사람이 읽을 수 있고, 기계가 처리하기에도 적합하며, 특정 플랫폼이나 언어에 묶이지 않는다. REST, 이벤트 스트리밍, 서버리스, IoT 같은 현대적 아키텍처에서 JSON이 기본 인터페이스로 쓰이는 배경이다.
RFC 8259는 JSON을 이름/값 쌍과 순서 있는 배열로 표현하는 텍스트 기반 데이터 교환 형식으로 규정한다. 사용할 수 있는 데이터 타입은 string, number, boolean, null, object({}), array([])다. 키는 따옴표로 감싼 문자열이어야 하고, 문자열에는 쌍따옴표를 사용한다.
유효한 JSON은 다음처럼 쓴다.
- 객체:
{"product":"pencil","price":1000} - 배열:
[{"id":1},{"id":2}] - 비유효 표현 교정:
{product:pencil,price,1000}→{"product":"pencil","price":1000}
애플리케이션 객체를 문자열로 만드는 과정은 직렬화(Serialization)이고, 문자열을 다시 객체로 읽어들이는 과정은 파싱 또는 역직렬화(Parsing/Deserialization)다.
변환 책임을 나누는 PRSMV 구성
JSON 처리는 하나의 라이브러리 호출로 끝나 보이지만, 운영 환경에서는 각 책임을 구분해 두는 편이 낫다.
Parser는 JSON 텍스트를 토큰화하고 문법 규칙에 따라 메모리의 객체로 바꾼다. 처리에 실패하면 예외와 오류 위치 정보를 반환하며, 대용량 데이터에는 스트리밍 파싱을 적용할 수 있다.
Renderer는 JSON을 사람이 읽기 쉬운 텍스트로 표현한다. pretty-print, 컬럼 정렬, 하이라이팅은 개발과 운영 관측성에 도움이 되지만 출력 크기를 늘린다는 대가가 있다.
Serializer는 POJO나 DTO 같은 애플리케이션 객체를 JSON 문자열로 만든다. 이 단계에서는 순환 참조와 날짜·이진 데이터의 처리 규칙을 정해야 한다.
Mapper는 필드 매핑, 타입 변환, 기본값 주입, 폴리모픽 바인딩처럼 객체와 JSON 사이의 변환 규칙을 관리한다. 스키마가 바뀔 때는 버전 관리와 하위 호환 전략이 필요하다.
Validator는 JSON Schema 등을 바탕으로 입력값을 검증한다. 조기 실패(Fail-fast)를 적용하면 오류를 격리할 수 있고, 규정 준수와 보안에도 도움이 된다.
API·이벤트·설정에서의 JSON 운영
REST/GraphQL API에서는 요청과 응답 본문을 JSON으로 표준화하고, v1, v2 같은 스키마 버저닝 및 Deprecation 정책을 운영할 수 있다. 필드 수준 Validation과 비즈니스 룰 검증은 분리하며, 오류 코드와 메시지 형식도 함께 정한다.
Kafka나 Kinesis를 통한 이벤트 스트리밍과 로그 처리에는 NDJSON(Newline-Delimited JSON)을 적용할 수 있다. 이 경우 스키마 레지스트리 연계, 압축, Backward/Forward compatibility를 함께 고려한다.
서버리스와 컨테이너 환경의 설정 관리에서도 환경별 JSON 설정을 주입할 수 있다. Secret은 별도로 분리하고, Validator→Dry-run→Rollout 순서의 변경 검증 파이프라인을 자동화한다.
입력 처리에서는 eval을 사용하지 않고 JSON.parse, Jackson, Newtonsoft 같은 표준 파서를 사용한다. 입력 Sanitization과 스키마 기반 Validator도 적용한다. 대용량 페이로드는 스트리밍 파서, 청크 처리, gzip/br 압축을 검토하며 깊은 중첩 구조는 줄인다. Pretty-print는 개발·디버그 환경에 한정하고 운영 경로에서는 Compact 모드를 적용하는 방식이 적합하다.
JSON을 선택할 때의 효과와 XML 대비 특성
XML과 비교하면 JSON은 페이로드 크기가 2060% 감소하고, 파싱 성능은 1.53배 개선될 수 있다(일반적 벤치마크 기준, 환경 차이 존재). 네트워크 비용과 처리 지연을 줄이는 데 연결된다.
언어와 플랫폼에 독립적이므로 여러 마이크로서비스와 프런트엔드 사이에 구조적 일관성을 확보하기 쉽다. 스키마 검증과 엄격한 파싱을 적용하면 런타임 오류를 줄일 수 있으며, 계약 기반 개발(Contract-first)은 변경 리스크를 완화한다.
| 지표 | JSON | XML |
|---|---|---|
| 성능 | 텍스트 양 적음, 파싱/직렬화 속도 우수 | 태그 과다로 크기 증가, 파싱 비용 높음 |
| 확장성 | 단순 구조, 수평 확장 유리 | 네임스페이스/스키마 복잡도 증가 |
| 일관성 | JSON Schema로 타입·제약 표현, 제한적 메타데이터 | XSD/DTD로 풍부한 제약, 강한 스키마 표준 |
| 안정성 | 엄격 파싱 + 스키마 검증으로 조기 실패 | 성숙한 검증 툴체인과 변환(XSLT) 생태계 |
| 운영 편의 | 개발 친화적, 디버깅 용이, 도구 다수 | 문서 지향 변환 용이, 레거시 연계 강점 |
검증부터 응답 렌더링까지의 처리 경계
입력은 Validator, Parser, Mapper, 트랜잭션 처리, Serializer, Renderer 순서로 흐른다. 스키마 또는 파싱 검증에 실패하면 즉시 실패 처리하고, 표준 오류 응답과 관측 지표를 남긴다. DB 쓰기 단계에는 트랜잭션 경계를 두어 성공 시 커밋하고 실패 시 롤백한다.
안전한 파싱과 직렬화 예시
전제조건: Node.js ≥ 18, Python ≥ 3.11
// JavaScript: 안전 파싱/직렬화
const payload = '{"product":"pencil","price":1000}';
try {
const obj = JSON.parse(payload); // eval 금지
obj.discount = 0.1;
const out = JSON.stringify(obj); // Compact
const pretty = JSON.stringify(obj, null, 2); // Pretty
console.log(out, "\n", pretty);
} catch (e) {
console.error("Invalid JSON:", e.message);
}
# Python: 파싱/검증(기본)
import json
raw = '{"product":"pencil","price":1000}'
try:
obj = json.loads(raw)
obj["discount"] = 0.1
out = json.dumps(obj, separators=(",", ":"), ensure_ascii=False)
print(out)
except json.JSONDecodeError as e:
print("Invalid JSON:", e.msg)