rest api 디자인할 때 get post put delete 메소드를 어떻게 구분하여 사용하시나요?

2013-04-19 09:18

스터디 그룹에 다음과 같은 질문이 올라와 이곳에 공개해 봅니다. 여러분은 어떻게 개발하고 계신가요? get, post외에 put, delete 같은 메소드도 사용하고 계시나요?

rest api 디자인할 때, get post put delete메소드를 어떻게 구분하여 사용하시나요? 예를들어 사용자관리에 대한 api를 만든다고 하면 필요한 api는 사용자목록/사용자(정보)조회/사용자추가/사용자(정보)수정/사용자삭제 정도가 되겠죠.

  1. 사용자 목록 - GET /users
  2. 사용자 정보 조회 - GET /users/{userid}
  3. 사용자 정보 수정 - PUT /users/{userid}
  4. 사용자 추가 - PUT /users/{userid}
  5. 사용자 삭제 - DELETE /users/{userid}

일단 처음엔 이렇게 정의 해봤습니다. 사용자 추가와 수정이 같은 Api가 된 것은 put을 사용할 경우 전체 사용자 중 userid로 접근된 사용자 리소스를 replace하거나 해당 리소스가 없다면 새로 생성하게되기 때문인데요.. 제가 맞게 이해하고 있는건지 모르겠네요^^; 또 DELETE는 전체 컬렉션 중 특정 리소스를 제거하는 용도라고 알고 있는데.. 이게 의미적으로만 맞으면 되는지.. 실제로 삭제될때만 사용해야하는건지 헷갈립니다. 예를들어 보통 사용자 삭제 는 실제 데이터 삭제가 아니라 해당 유저의 상태만 삭제로 변경하곤 하쟎아요? 그럼 이게 의미적으로 삭제가 맞으니 delete메소드를 사용하면 되는건지... 실제로 삭제되는것이 아니니 /users/{userid}/disable 이렇게 행위를 표현해주면 되는것일까요? 후자가 맞다면 이때는 POST/PUT 중 어떤게 맞는걸까요?

에고... 요즘 진행중인 플젝에 rest api를 적용해보려는데 처음하다보니 쉽지가 않네요. 모바일로 작성하다보니 질문이 간결하지 못해 이해에.어려움이 있을지도 모르겠어요. 끝까지 읽어주셔서 감사드리고... 제가 산으로 가지 않도록.. 경험 있으시다면 도움 투척 부탁드리옵니다^^

1개의 의견 from FB

2개의 의견 from SLiPP

2013-04-19 23:04

DELETE에 대해

HTTP는 프로토콜이기 때문에, 다루는 범위는 서버와 클라이언트가 나누는 대화로 제한됩니다. 즉 DELETE 요청을 받은 서버가 실제로 해당 리소스에 대응하는 레코드나 파일을 삭제하느냐 아니냐는 별로 의미가 없다고 봅니다. 클라이언트가 DELETE 요청을 보내자, 서버가 200 OK로 응답했고, 다시 해당 리소스에 대해 GET 요청을 보내자, 서버가 404 Not Found로 응답한다면 HTTP로 자연스럽게 대화하는 것으로 볼 수 있습니다. 서버에서 어떻게 삭제할 것인가는 전적으로 서버의 구현에 달린 문제입니다.

그러나 클라이언트 입장에서 볼 때도 삭제되는 것이 아닌 경우도 있을 수 있는데요. 즉, 말씀하신 것과 마찬가지로 삭제가 실제로 삭제가 아니라 일시적으로 사용할 수 없는 상태가 되는 경우입니다. 사용자를 삭제한 경우, 해당 사용자에 대해 GET으로 접근했을 때 404 Not Found가 아니라 403 Forbidden으로 응답하도록 하고, 권한이 있는 특정 사용자(예: 사이트 관리자)는 여전히 해당 사용자를 열람할 수 있다면, 이는 '삭제'라고 할 수 없을 것이며, 따라서 이러한 '삭제(?)' 요청이라면 DELETE 메소드를 사용하는 것은 자연스럽지 않습니다.

다만 HTTP 명세는 DELETE 요청에 대해 서버가 반드시(MUST) 해당 리소스를 삭제해야 한다고 정의하지는 않았습니다. 따라서 클라이언트는 DELETE 요청에 대해 200 OK로 응답을 받았다 하더라도, 해당 리소스가 삭제되었음을 확신하고 동작해서는 안될 것입니다.

따라서 이런 경우엔 생각하신것과 비슷하게, /users/{userid}/state (HTTP에서 url의 path는 리소스를 가리키는 것이므로, 명사가 적절하다고 봅니다) 와 같은 url에 PUT 요청으로 "pending" 같은 문자열을 body에 담아 전송하여 사용자의 상태를 "대기"로 변경할 수도 있을 것이며, /users/{userid}에 POST 요청으로 { "state": "pending" } 과 같은 json entity를 전송하는 방법도 가능할 것입니다.

흔히 POST 요청은 "새로운 리소스를 서버에 만드는 것"으로 알려져있기 때문에 후자의 경우는 적절하지 않아 보일 수 있습니다. 실제로 RFC 2616에 POST 메소드는 url에 속한 리소스(a new subordinate of the resource identified by the Request-URI)를 만들기 위해 사용한다고 설명하고 있습니다. 그러나 애매하게도 명세에는 서버가 처리해주기를 바라는 데이터 덩어리(block of data)를 제공하기 위해서도 POST를 사용할 수 있다고도 되어있습니다.1 이것은 모호한 표현이기 때문에 수정이 필요하다는 의견이 HTTP 워킹그룹 메일링리스트에서 제기되었으며2, 조만간 IETF에 제출될 것으로 보이는 HTTP/1.1 개정판에서는 POST 요청에 대한 설명이 "서버에 보낸 데이터를 대상 리소스가 처리하도록 하는 요청"으로 바뀌게 됩니다.3

이와 같이 명세에 모호하거나 잘못된 표현이 있는 경우 이를 그대로 따라야 하는가는 좀 어려운 문제일 수 있는데, 위의 경우 모호함이 있는 것은 "설명"이지 "요구사항"이 아니기 때문에(요구사항인 경우에는 문장에 SHOULD, SHOULD NOT, MUST, MUST NOT 등을 넣어서 명시적으로 알 수 있게 합니다), 곧이 곧대로 따르지 않는다고 하여 "HTTP 명세를 따르지 않는다"고 말할 수는 없습니다. 따라서 저라면 그다지 죄책감(?)을 느끼지 않고 POST를 사용하겠습니다.

2013-04-23 05:15

저도 그냥 post가 편했던 것 같습니다.

왠지 명세대로 가줘야 모범생(?)인 것 같은... 그런 기분을 저도 간혹 느끼는데...

Rest API를 쓰는 개발자 입장에서 한 번 생각해보면...

웹 생태계를 속속들이 알고 있는 분일수도 있는 반면 이제 막 입문하셔서 호출조차 어려워 하실 수도 있습니다. (실력이 없으셔서 그런게 아니라... 가령 c++로 게임엔진만 전문적으로 프로그래밍 하시던 분인데 어쩔 수 없는 요구때문에 급하게 rest api를 가져다 쓰고 싶으실 수도 있지 않을까요? )

그런 분들에게 put과 delete로도 날릴 수 있다고 말씀드리는 것보다

샘틀놀이님이 말씀하신 것처럼 심플하게 post만 제공해드리니 더 편해하셨던 것같아서요.

의견 추가하기

연관태그

← 목록으로