카카오테크캠퍼스 선물하기 API를 구현하면서 삭제 요청에 필요한 값을 어디에 담아야 할지 고민했다. 기능 자체는 단순했다. 특정 리소스를 삭제하는 API였다.
처음에는 DELETE 요청의 Body에 값을 넣어도 된다고 생각했다. 서버에서는 Body를 읽을 수 있기 때문이다. 하지만 API를 쓰는 쪽까지 생각하면 애매한 부분이 있었다. 클라이언트, 중간 프록시, 문서화 도구가 DELETE Body를 모두 같은 방식으로 다룬다고 보기 어려웠다. API는 서버 코드만 맞으면 끝나는 것이 아니라, 클라이언트와 함께 맞춰야 하는 약속에 가깝다고 느꼈다.
이 글은 DELETE 요청에서 Body 사용을 피하고, 삭제 대상을 더 잘 드러내는 API 형태를 선택한 기록이다.
처음 생각한 방식
처음에는 삭제에 필요한 값을 Body에 넣는 방식을 생각했다.
DELETE /api/wishlist
Content-Type: application/json
{
"productId": 1
}
서버 입장에서는 처리할 수 있었다. JSON으로 값을 받으면 나중에 필드를 추가하기도 쉬워 보였다. 하지만 API를 사용하는 입장에서는 DELETE 요청의 Body가 바로 눈에 들어오지 않을 수 있었다.
특히 삭제 대상이 하나의 리소스로 분명하다면, Body보다 URI에 삭제 대상을 드러내는 편이 읽기 쉬웠다.
Query Parameter 검토
두 번째로는 Query Parameter를 검토했다.
DELETE /api/wishlist?productId=1
이 방식도 사용할 수 있었다. 다만 삭제 대상이 리소스 식별자라면 Query Parameter보다 Path Variable이 더 어울린다고 봤다. Query Parameter는 필터나 옵션처럼 보이기 쉬워서, 삭제 대상 자체를 표현하기에는 조금 애매했다.
해결 방법
최종적으로는 삭제할 대상을 URI 경로에 드러내는 형태로 정리했다.
DELETE /api/wishlist/items/{productId}
이 방식은 요청을 보는 사람도 어떤 리소스를 삭제하는지 바로 알 수 있다. API 문서에서도 설명이 단순해지고, 클라이언트에서도 사용 방식을 이해하기 쉬웠다.
DELETE Body가 절대 불가능하다는 뜻은 아니었다. 다만 이 프로젝트의 요구사항에서는 삭제 대상이 분명했기 때문에, Body를 쓰는 것보다 URI에 표현하는 방식이 더 적절해 보였다.
확인한 내용
API 설계에서 확인한 기준은 아래와 같았다.
- 삭제 대상이 리소스 식별자인가
- 요청만 보고 의도를 알 수 있는가
- 클라이언트와 문서화 도구가 다루기 쉬운가
- 나중에 API를 보는 사람이 의미를 이해하기 쉬운가
단순히 서버에서 처리 가능하다는 이유만으로 선택하지 않으려고 했다. API는 서버 구현만의 문제가 아니라, 클라이언트와 함께 쓰는 약속이기 때문이다.
정리
이번 경험을 통해 REST API 설계에서는 동작 여부뿐 아니라 요청 형태가 얼마나 읽기 쉬운지도 같이 봐야 한다는 점을 다시 확인했다.
DELETE 요청에 Body를 넣을 수 있는지보다, 이 API가 어떤 리소스를 삭제하는지 잘 드러나는지를 더 많이 봤다. 그래서 삭제 대상이 분명한 경우에는 Path Variable로 표현하는 방식을 선택했다.