Rails 8 업그레이드 중 JSON 응답에서 중복 키 발생 사례

Rails 8 upgrade story: duplicate keys sneaking into our JSON responses | Arkency Blog

작성자
발행일
2025년 09월 25일

핵심 요약

  • 1 Rails 8 업그레이드 후 `render json:`의 내부 최적화로 인해 기존에 숨겨져 있던 중복 키 문제가 JSON 응답에서 표면화되었습니다.
  • 2 문제는 Ruby 해시에서 동일한 키가 문자열과 심볼 형태로 동시에 존재할 때 발생하며, Rails 7에서는 `as_json`이 이를 암묵적으로 정규화하여 중복을 방지했습니다.
  • 3 `json` 젬의 경고 기능 및 `ActiveSupport`의 `disallowed_deprecation_warnings` 설정을 활용하여 개발 및 테스트 환경에서 중복 키 문제를 사전에 감지하고 방지할 수 있습니다.

도입

Rails 7.2.2.2에서 8.0.2.1로의 업그레이드는 예상외로 순조로웠으며, 배포 후 초기에는 어떠한 예외나 불안정성도 감지되지 않았습니다. 그러나 시간이 지나면서 외부 애플리케이션에서 JSON API를 소비하는 과정에서 문제가 보고되기 시작했습니다. 문자열이어야 할 식별자가 갑자기 정수로 전달되거나, JSON 응답에 중복된 키가 포함되는 현상이 발생하여, 결국 변경 사항을 롤백하고 디버깅에 착수하게 되었습니다.

이 문제의 근원은 ActiveRecord 객체를 직렬화하는 코드에 있었습니다. 특히, attributes.merge(id: public_id)와 같은 코드가 원인이었습니다. 이 코드는 기본 키를 서비스 간 통신에 사용되는 공개 식별자로 대체하려는 의도였으나, attributes가 문자열 키를 가진 해시를 반환하고 여기에 심볼 키(:id)로 값을 병합하면서 동일한 id에 대해 문자열 키와 심볼 키가 공존하는 해시({"id" => 1, :id => "one"})를 생성했습니다.

Rails 버전별 동작 변화

  • Rails 7.2: render json: 호출 시 내부적으로 as_json을 사용했습니다. as_json은 키를 정규화(심볼 키를 문자열로 변환)하고 중복을 제거하여, 최종 JSON 응답에는 항상 마지막에 제공된 값이 사용되어 중복 키 문제가 표면화되지 않았습니다.

  • Rails 8.0: Rails 8의 성능 최적화 커밋은 render json: 호출 시 템플릿 옵션이 없는 경우 as_json 호출을 건너뛰는 “고속 경로(fast path)”를 도입했습니다. 이 고속 경로는 키 정규화 및 중복 제거 로직을 우회하여, 혼합 키 해시({"id" => 1, :id => "one"})가 그대로 JSON 인코더에 전달되어 {"id":1,"id":"one"}과 같이 중복 키가 포함된 JSON 응답이 생성되었습니다.

변경 로그의 혼란

ActiveSupport 7.1.3 변경 로그에는 “ActiveSupport::JSON.encode가 중복 키를 방지하도록 수정”이라는 내용이 있었으나, 이 수정 사항은 7.1.4에서 문서화되지 않은 채 롤백되어 혼란을 야기했습니다.

중복 키 방지 및 감지 전략

이러한 회귀를 방지하기 위한 몇 가지 방법이 있습니다.

  • 요청 스펙(Request Specs): JSON 응답 본문의 정확한 형태를 검증하는 요청 스펙을 작성하면 중복 키가 즉시 불일치로 감지됩니다.

  • json 젬 활용: json 젬 2.14.0 버전부터는 동일한 키가 문자열과 심볼 형태로 동시에 존재할 경우 경고를 발생시키며, 3.0 버전에서는 기본적으로 오류를 발생시킬 예정입니다.

  • ActiveSupport 설정: config.active_support.disallowed_deprecation_warnings를 사용하여 json 젬의 경고를 ActiveSupport의 감가상각 프레임워크로 전달하고, config.active_support.disallowed_deprecation = :raise를 설정하여 테스트 또는 개발 환경에서 이를 오류로 처리할 수 있습니다.

이러한 다층적인 접근 방식은 모든 응답 본문을 상세히 검증하지 못하더라도, 자동화된 테스트나 수동 테스트 과정에서 중복 키 문제를 조기에 발견하여 실패하도록 유도할 수 있는 가벼운 안전장치가 됩니다.

결론

결론적으로, JSON 응답의 중복 키 문제는 개발팀의 코드 내부에 존재했던 잠재적인 버그가 Rails 8의 성능 최적화로 인해 표면화된 사례입니다. 이는 Rails의 암묵적인 키 정규화 동작에 의존하고 있었음을 보여줍니다. 이러한 종류의 회귀를 방지하기 위해서는 응답 본문을 엄격하게 검증하는 요청 스펙을 작성하는 것이 가장 확실한 방법입니다. 더불어, `json` 젬의 경고 기능을 활용하고 `ActiveSupport`의 감가상각 경고 설정을 통해 개발 및 테스트 환경에서 중복 키 문제를 조기에 감지하도록 시스템을 구성하는 것이 중요합니다. 이처럼 다층적인 방어 전략을 통해 예기치 않은 버그가 프로덕션 환경으로 유입되는 것을 효과적으로 방지할 수 있습니다.

댓글 0

댓글 작성

0/1000
정중하고 건설적인 댓글을 작성해 주세요.

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!