API 응답을 붙여넣었더니 빨간 줄 하나에 Unexpected token. 어디가 문제인지 눈으로 훑다가 결국 괄호를 하나씩 세고 있습니다. JSON은 규칙이 단순한데, 그 단순함 때문에 작은 실수 하나가 전체 파싱을 막습니다. 어디가 깨졌는지부터 찾는 법을 정리합니다.
깨진 JSON, 어디가 문제인지부터
JSON 파서는 첫 번째 오류에서 멈추고 그 위치를 알려줍니다. 메시지를 그냥 지나치기 쉽지만, 거기에 줄과 열이 들어 있습니다.
예를 들어 { "name": "PiPi", "role": "editor", } 처럼 마지막 값 뒤에 쉼표를 남기면, 파서는 Expected double-quoted property name in JSON at position 40 (line 4 column 1) 라고 답합니다. PiPi Worlds JSON 포맷터는 이 줄·열을 그대로 짚어 주므로, 닫는 괄호가 있는 4번째 줄로 바로 가면 됩니다. 범인은 그 바로 앞의 trailing comma입니다.
가장 자주 나오는 오류는 정해져 있습니다.
| 오류 | 증상 |
|---|---|
| trailing comma | 마지막 요소 뒤 불필요한 쉼표 |
| 따옴표 누락 | 키나 문자열을 큰따옴표로 안 감쌈 |
| 괄호 짝 안 맞음 | {·[ 를 닫지 않음 |
| 콜론 누락 | 키와 값 사이 : 빠짐 |
JSON은 작은따옴표, 주석, trailing comma를 허용하지 않습니다(RFC 8259). 자바스크립트 객체 리터럴과 헷갈려서 나는 실수가 많습니다.
보기 좋게 정렬하거나, 한 줄로 압축하거나
유효한 JSON이라면 들여쓰기를 입혀 구조를 한눈에 볼 수 있습니다. 2칸·4칸·탭 중 팀 컨벤션에 맞는 들여쓰기를 고르면 됩니다.
반대로 전송 크기를 줄여야 할 땐 압축으로 모든 공백을 제거합니다. { "a": 1, "b": [1, 2, 3] } 는 {"a":1,"b":[1,2,3]} 한 줄이 됩니다. 같은 데이터를 보기용과 전송용으로 오가는 작업이라 자주 쓰게 됩니다.
키 정렬: 두 API 응답을 줄 단위로 비교하기
덜 알려졌지만 디버깅에서 강력한 기능이 키 정렬입니다. 객체 키를 알파벳순으로 재배열합니다.
서버 두 대가 같은 데이터를 주는데 키 순서만 달라 diff가 온통 빨갛게 뜬 적이 있을 겁니다. 양쪽을 키 정렬로 통일하면, 순서 차이는 사라지고 진짜로 다른 값만 남습니다. 예를 들어 {"name":"PiPi","id":42,"active":true} 는 active, id, name 순으로 재배열돼, 다른 응답과 줄을 맞춰 비교할 수 있습니다.
큰 숫자가 조용히 바뀌는 함정
이건 알아두지 않으면 한참 헤맵니다. JSON 숫자는 자바스크립트에서 IEEE-754 배정밀도로 파싱됩니다.
문제는 안전 정수 범위를 넘어설 때입니다. {"id": 12345678901234567890} 을 정렬하면 {"id": 12345678901234567000} 이 나옵니다. 뒷자리가 조용히 000으로 바뀐 겁니다. 자바스크립트가 안전하게 다루는 정수는 2^53, 즉 9007199254740991 까지이기 때문입니다. Discord나 트위터의 ID처럼 큰 정수는 이 범위를 넘기 일쑤입니다. 정확한 자릿수가 필요하면 원본 JSON에서 그 값을 문자열("12345678901234567890")로 두는 게 안전합니다. 도구로 한 번 돌려 보면 내 데이터에 이 함정이 있는지 바로 보입니다.
그 API 응답, 어디에 붙여넣고 있나
마지막으로 짚을 점입니다. 디버깅하려고 붙여넣는 JSON에는 액세스 토큰, 내부 ID, 개인정보가 섞여 있는 경우가 많습니다. 입력을 서버로 전송하는 온라인 포맷터라면, 그 민감한 응답이 통째로 제3자에게 넘어갑니다.
PiPi Worlds JSON 포맷터는 파싱이 전부 브라우저 안에서 실행됩니다. 입력은 서버로 전송되지 않으므로 토큰이 든 설정 파일이나 API 응답도 안심하고 정리할 수 있습니다. JSON 안에 들어 있는 base64 값이 궁금하면 Base64 도구, 그 값이 JWT라면 JWT 디코더로 바로 이어서 확인하면 됩니다.