Next.js와 FastAPI 사이에서 조용히 깨진 JSON, 이렇게 막았어요
프론트에서 보낸 값이 백엔드에서 소리 없이 사라질 때, Date·undefined·BigInt 손실을 zod 왕복 테스트로 막은 방법을 정리했어요.
Next.js와 FastAPI 사이에서 조용히 깨진 JSON, 이렇게 막았어요
프론트에선 분명히 값을 넣어 보냈는데, 백엔드 로그를 보면 그 필드가 없어요. 에러도 안 나고요. 혹시 이런 적 없나요? 라이프케어로그 플랜 시리즈를 만들면서 저를 제일 오래 붙잡은 버그가 바로 이 조용한 실종이었어요.
JSON은 자바스크립트의 사진이 아니에요
가장 큰 착각은 JSON.stringify가 자바스크립트 값을 그대로 옮겨 준다고 믿는 거예요. 실제로 JSON이 표현할 수 있는 타입은 문자열·숫자·불리언·null·객체·배열, 딱 6가지예요. 나머지는 조용히 바뀌거나 사라져요.
직접 넣어 보니 이렇더라고요.
undefined값을 가진 필드는 통째로 빠져요. 객체에 3개를 담아 보내도 도착하면 몇 개만 남아요.Date는 문자열(ISO 8601)로 바뀌어서 넘어가요. 받는 쪽에서 다시Date로 되살리지 않으면 그냥 글자예요.BigInt는 아예 던져요(TypeError).Number.MAX_SAFE_INTEGER, 즉 2^53-1(약 9,007조)을 넘는 정수를 다루면 여기서 막혀요.
플랜씨(plan-c)처럼 돈을 계산하는 화면은 이게 남 얘기가 아니에요. 복리나 큰 금액을 다루다 보면 안전 정수 범위를 넘는 값이 나오거든요.
- undefined 필드는 실종
- Date는 문자열로 변신
- BigInt는 TypeError
clone 용도로 stringify를 쓰지 마세요
JSON.parse(JSON.stringify(x))로 객체를 복사하는 패턴, 저도 예전에 썼어요. 근데 이건 복사가 아니라 손실 필터예요. 같은 런타임 안에서 복사만 필요하면 structuredClone이 정답이에요. 다만 이건 API 경계를 넘는 계약까지 대신해 주진 않아요.
경계에는 zod 왕복 테스트를 두세요
제가 자리 잡은 방법은 3단계예요.
Date·BigInt 같은 값은 보낼 때 문자열로 바꾸고(encode), 받을 때 다시 타입으로 되살리는(decode) 규칙을 zod 스키마에 명시해요. 그리고 encode → decode를 거친 값이 원래 값과 같은지 확인하는 왕복 테스트를 붙여요. 핵심은 이 테스트가 몇 줄 안 된다는 거예요. 값 하나 넣고, 왕복시키고, 같은지 비교. 이 짧은 걸 돌려 보니 배포 전에 "필드가 사라지는" 사고가 눈에 띄게 줄었어요.
날짜는 특히 조심해야 해요. new Date('2026-05-14')는 자정 UTC로 해석돼서, 한국 시간으로 보면 하루가 밀릴 수 있어요. 플랜비(plan-b)에서 회비 납부일처럼 날짜만 다룰 땐 아예 Date 객체 대신 문자열(YYYY-MM-DD)로 주고받는 편이 안전했어요.
정리하면
JSON은 상태 스냅샷이 아니라 손실 가능한 교환 형식이에요. 경계를 넘는 값이 Date·undefined·BigInt·NaN이라면, 스키마로 규칙을 적고 왕복 테스트 한 개로 지켜 두세요. 10분이면 붙이는데, 조용히 사라지는 버그를 찾아 밤새우는 시간을 아껴 줘요.
관련 글
댓글
아직 댓글이 없어요. 첫 댓글을 남겨주세요.