PUT 메서드에 'Optional' 매개변수를 넣었을 때 벌어지는 일
API를 설계하다 보면 “수정” 기능을 만들 때 관성적으로 PUT을 선택하곤 합니다. 저 또한 최근 프로젝트에서 수정 기능을 구현하며 모든 매개변수를 Optional(선택 사항)로 열어두고 PUT을 사용했다가, PUT의 진짜 의미와 동작 방식을 다시 공부하게 된 경험이 있습니다.
나의 실수: “PUT인데 왜 다 안 보내도 돼?”
처음 API 명세서를 작성할 때, “사용자가 수정을 안 하고 싶은 필드도 있을 테니까”라는 생각으로 백엔드 매개변수를 모두 옵셔널하게 설정했습니다. 이름만 바꾸고 싶으면 이름만 보내면 될 거라 생각해, PUT 메서드에 address(optional), tele(optional), category(optional), rating(optional)처럼 매개변수를 전부 옵셔널로 설정한 것입니다.
하지만 이 설계는 PUT의 정의와 정면으로 충돌하는 방식이었습니다.
PUT의 본질은 ‘교체’다
PUT 메서드는 해당 리소스의 전체 상태를 새로운 데이터로 통째로 갈아 끼우는 것입니다.
1. 필드를 누락하면 어떻게 될까?
만약 서버가 엄격하게 구현되어 있다면, PUT 요청에서 누락된 필드는 null로 저장되거나 기본값으로 초기화되어야 합니다. 예를 들어 name만 보내고 age를 안 보냈다면, 사용자의 나이가 0이나 null이 되어버리는 대참사가 발생할 수 있습니다.
2. 멱등성(Idempotency)의 유지
PUT은 여러 번 호출해도 결과가 항상 같아야 합니다. 그런데 매번 다른 ‘옵셔널’한 값들을 조합해서 보낸다면, 서버의 상태가 예측 불가능하게 변할 수 있어 PUT의 핵심 원칙인 멱등성을 해칠 위험이 있습니다.
해결책: 부분 수정은 PATCH에게
제가 원했던 “원하는 것만 골라서 수정하기”는 PUT이 아니라 PATCH의 역할이었습니다. PUT은 리소스 전체를 가져와서 수정하고 다시 전체를 보낼 때 쓰고, PATCH는 리소스의 일부 필드만 업데이트하고 싶을 때 씁니다.
주니어 개발자로서 이 차이를 명확히 인지하지 못했을 때는 “그냥 수정이니까 PUT 쓰면 되는 거 아냐?”라고 가볍게 생각했지만, 실제 데이터의 무결성을 생각한다면 아주 큰 차이였습니다.
배운 점: 설계의 의도를 명확히 하자
이번 경험을 통해 매개변수 하나를 Optional로 둘 때도 메서드의 성격에 맞는지 고민해야 한다는 것을 배웠습니다. PUT을 쓸 거라면 클라이언트에게 “반드시 모든 데이터를 실어서 보내라”고 강제하거나, 프론트엔드에서 기존 데이터를 다 가져온 뒤 수정된 부분만 합쳐서 전체를 쏘아줘야 합니다. Optional이 필요하다면 메서드를 PATCH로 변경해 “이 API는 부분 수정용입니다”라고 의도를 명확히 밝혀야 합니다.
결국 전체를 갈아 끼울 때는 PUT, 필요한 필드만 손볼 때는 PATCH입니다. 단순히 기능이 돌아가는 것을 넘어, HTTP 프로토콜의 약속을 지키는 설계가 얼마나 중요한지 깨달은 시간이었습니다.