개발 slecs

기기 등록 엔드포인트 500 오류를 ENUM 불일치로 잡다

목차

/device 엔드포인트에서 500이 터지고 있었다. 그것도 앱 쪽 신규 기기 등록 흐름에서.


배경: 왜 500이 났는가

처음엔 서버 로그만 봤을 때 딱히 명확한 원인이 안 보였다. 요청 자체는 들어오는데 서버가 Internal Server Error를 뱉는 구조. 이런 류의 500은 크게 두 가지 패턴에서 온다 — 서버가 예상한 형식과 다른 값이 들어오거나, 타입 자체가 맞지 않거나.

결국 페이로드를 까보니 두 군데가 문제였다.

  1. platform 필드가 ENUM으로 정의된 서버 계약을 앱 쪽이 임의 문자열로 보내고 있었음
  2. 푸시 수신 가능 시각 관련 필드의 타입이 서버 스펙과 불일치

서버 입장에서는 ENUM으로 선언해놓은 필드에 허용되지 않은 값이 오거나, 파싱 대상 타입이 달라지면 그냥 500 던지는 게 기본 동작이다. 별도의 validation 레이어가 400을 잡아주지 않는 구조라면 더더욱. 이건 앱-서버 계약이 느슨하게 관리될 때 자주 발생하는 패턴이다.


수정 내용

변경이 들어간 파일은 api_client.dartdevice_repository.dart 두 곳이다.

파일 역할 이번 수정 포인트
api_client.dart HTTP 요청 구성, 직렬화 처리 platform 값을 ENUM 정의에 맞게 정정
device_repository.dart 기기 등록/조회 도메인 로직 푸시 가능 시각 필드 타입 정정

api_client.dart 쪽은 platform 필드를 서버가 기대하는 ENUM 값 그대로 넘기도록 수정한 게 핵심이다. 앱 내부적으로 플랫폼을 어떻게 표현하든, 네트워크 레이어를 넘기 직전에 반드시 계약된 ENUM 값으로 변환하는 게 맞다. 예를 들면 이런 식이다.

// Before — 임의 문자열 그대로 전달
'platform': Platform.isIOS ? 'ios' : 'android',

// After — 서버 ENUM 계약에 맞게 매핑
'platform': Platform.isIOS ? 'IOS' : 'ANDROID',

사소해 보이지만 대소문자 하나 차이로 서버 ENUM 파싱이 실패하고 500이 나는 건 흔한 실수다. 특히 초기 계약 시점에 양쪽 문서화가 느슨하면 이런 게 한참 뒤에야 발견된다.

device_repository.dart 쪽 푸시 시각 타입 문제도 비슷한 맥락이다. 푸시 수신 허용 시간대 같은 필드는 String으로 보내야 할 걸 int로 보내거나, ISO 포맷이어야 할 걸 epoch timestamp로 보내는 불일치가 자주 생긴다. repository 레이어에서 도메인 모델을 네트워크 DTO로 변환할 때 이 타입 캐스팅을 확실히 처리해주는 게 중요하다.


회고

솔직히 이런 버그는 API 계약 문서와 실제 구현 사이의 drift에서 기인하는 경우가 대부분이다. 서버가 스펙을 바꾸면서 앱 쪽 공유가 제때 안 됐거나, 초기 구현 때 문서 확인 없이 감으로 짠 게 그대로 올라간 케이스.

팀 차원에서 이런 문제를 줄이려면:

  • 앱-서버 간 타입 계약을 OpenAPI 스펙이나 별도 계약 문서로 명시하고, 변경 시 양쪽이 동시에 인지하는 프로세스가 필요함
  • 특히 ENUM 필드는 "허용값 목록"을 코드에 상수로 박아두고, 서버 스펙 변경 시 앱도 같이 업데이트하는 루틴을 명확히 해야 함
  • 기기 등록처럼 앱 런타임 초기에 호출되는 API가 500을 내면 이후 기능 전체에 영향이 생길 수 있어서, 이 엔드포인트는 특히 회귀 테스트 우선순위를 높게 잡을 필요가 있음

핀포인트 수정이라 변경 라인 수 자체는 크지 않지만, 방치됐으면 기기 등록 전체가 뚫린 상태로 운영됐을 거다. 작은 픽스가 임팩트는 큰 경우.

다음


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.