API 필드 제거와 배포 순서: 필드를 지우면 읽는 쪽이 터진다

API에서 필드를 제거하면 그 값을 읽던 쪽이 깨진다. 부분 수정 DTO의 null 덮어쓰기, 항상 200을 주는 API가 버그를 숨기는 것, 프론트/백엔드 배포 순서를 정하는 기준.

조회
목차

주문 화면을 단순하게 만드는 작업이었다. 주문할 때 받던 정보 일부(받는 사람 이름, 연락처, 상세주소)를 빼고 나중 단계인 배송지 확인으로 옮기는 일.

화면에서 입력칸 지우고 API에서 필드 빼면 끝날 줄 알았다.

깨진 곳이 셋이었는데, 셋 다 지운 자리가 아니었다

전부 그 값을 읽던 자리였다. 그리고 셋 다 조용히 깨졌다.

1. 대조할 기준이 없으면 전부 실패로 판정된다

배송 대행사에서 받은 주소와 주문할 때 받은 주소를 비교해서, 같으면 통과시키는 함수가 있었다.

// 대행사 값 없음            → 검사 안 함
// 대행사 값 있음 + 저장값 없음 → 불일치   ← 여기
// 둘 다 있음                → 정리해서 비교
private boolean isMismatch(String externalValue, String storedValue) {
    if (!hasText(externalValue)) return false;
    if (!hasText(storedValue))   return true;   // 대조 불가 = 실패
    return !normalize(externalValue).equals(normalize(storedValue));
}

"대조할 기준이 없으면 실패"는 안전한 설계다. 확인 안 되는 걸 통과시키는 것보단 낫다.

문제는 주문에서 그 기준값을 안 받게 되면 신규 주문 전부가 이 분기를 탄다는 거다. 통과율 0%.

게다가 화면에 안 보였다. 고객에게는 보류 상태를 "확인 중"으로 보여주고 있었으니까. 그래서 증상이 "영원히 확인 중 + 배송 무기한 보류"다. 에러 로그도 안 남는다. 정상 동작으로 기록되니까.

2. 항상 200을 주는 API는 진짜 실패도 숨긴다

주문 조회가 이메일과 연락처로 찾고 있었다. 연락처를 안 받게 됐으니 조회가 영구 실패한다.

근데 이 API는 주문 존재 여부를 숨기려고 항상 성공을 반환한다. 없는 이메일을 넣어도 "메일을 보냈습니다"가 뜬다. 남의 주문이 있는지 떠보는 걸 막는 장치다.

방어는 제대로 동작했다. 실제 버그까지 같이 숨겼을 뿐이다.

클라이언트는 성공을 받고, 서버는 200을 남기고, 메일만 영영 안 온다.

3. 폼에 입력칸이 없는 필드가 요청 객체에 남아 있으면 지워진다

관리자 주문 수정 요청 객체에 연락처 필드가 있었다. 근데 수정 폼에는 연락처 입력칸이 없다 — 다른 화면으로 옮겼으니까.

public record OrderUpdateRequest(
    String memo,
    String phone,     // 폼에 입력칸이 없다 → 항상 null 로 온다
    ...
) {}

관리자가 메모만 고치고 저장하면 연락처가 지워진다.

부분 수정에서 "필드가 안 왔다"와 "빈 값으로 바꿔달라"가 구분되지 않는 고전적인 문제다. 이번엔 계기가 "폼에서 입력칸을 지웠다"라서 요청 객체를 열어볼 이유가 없었다.

어떻게 고쳤나

1. 대조 기준의 출처를 옮겼다. 판정 로직은 한 줄도 안 고쳤다. 그 함수가 읽는 값을 만드는 지점만 새 입력 단계로 옮겼더니 그대로 동작했다. 읽는 쪽이 아니라 쓰는 쪽을 고치는 게 맞았다.

2. 조회 조건에서 연락처를 뺐다. 여기서 배운 건 고친 방법보다 못 찾을 뻔한 이유 쪽이다. 이 버그는 테스트로도 안 잡힌다 — API는 200을 반환하니 계약상 정상이니까. 코드를 눈으로 읽어서 찾았다.

3. 필드를 요청 객체에서 아예 지웠다. null을 무시하도록 설정을 바꾸는 방법도 있는데, 그러면 "일부러 비우기"가 영영 불가능해진다. 이 필드는 다른 경로에서만 수정하는 게 맞아서 아예 못 건드리게 지웠다.

배포 순서 — 필드를 지울 땐 백엔드가 먼저

같은 문제의 연장이다. 프론트와 백엔드는 동시에 배포되지 않는다. 사이에 몇 분이 뜬다.

순서백엔드프론트그 사이
백엔드 먼저필드 안 받음아직 보냄정상 — 여분 필드는 무시
프론트 먼저필수라고 요구안 보냄주문 전부 400

여분 필드가 무시되는 건 JSON 파서 설정 덕이다. "모르는 필드가 와도 에러 내지 말고 무시해라"는 설정이 있어야 "받아주되 무시하는" 구간이 생기고, 그 구간이 있어야 두 배포 사이가 안전하다.

남길 것

  • 필드를 지우면 쓰는 쪽이 아니라 읽는 쪽이 터진다. 지우기 전에 그 값을 읽는 코드를 전부 찾는다. 검색할 건 필드명이 아니라 그 값이 흘러가 담기는 변수와 컬럼이다.
  • "없으면 실패" 판정은 위쪽 데이터가 사라지면 전 건 실패가 된다. 옳은 설계지만, 그 기준값의 출처를 아는 사람만 안전하게 고칠 수 있다.
  • 가려놓은 화면은 버그도 같이 가린다. 보류를 "확인 중"으로 보여주거나 항상 200을 주는 코드는 실패를 정상으로 기록한다. 테스트로 안 잡히니 눈으로 읽어야 한다.
  • 부분 수정 요청 객체는 폼과 짝이다. 폼에서 입력칸을 지웠으면 요청 객체에서도 지운다.
  • 받아주는 쪽을 먼저 넓히고 배포한다. "받아주되 무시" 상태를 먼저 올리면 두 배포 사이가 안전하다.

더 봐야 할 것

  • "기준값이 없음"과 "값이 다름"을 다른 상태로 구분하면 이번 같은 사고가 화면에 드러날까
  • 가려놓은 응답에 내부용 원인 코드를 따로 남기는 게 일반적인 관행인지
  • 부분 수정에서 "안 보냄"과 "비우기"를 구분하는 방법으로 실무에서 뭘 쓰는지

사이트 내 검색

제목·태그·설명·본문으로 발행 글을 찾습니다