[작성일: 2023. 09. 06]
HTTP API
회원 정보 관리 API URI를 설계해보자.
- 회원 목록 조회 /read-member-list
- 회원 조회 /read-member-by-id
- 회원 등록 /create-member
- 회원 수정 /update-member
- 회원 삭제 /delete-member
이렇게 설계한 URI는 좋은 URI 설계일까? 정답은 NO!
가장 중요한 것은 리소스 식별하는 것이다.
그렇다면 리소스란 무엇일까? 회원을 등록하고 수정하고 조회하는 게 리소스를 뜻하는 것은 아니다. '회원'이라는 개념 자체가 바로 리소스라고 할 수 있다.
리소스는 어떻게 식별하는 게 좋을까? 회원을 등록하고 수정하고 조회하는 것을 모두 배제해야 한다. 회원이라는 리소스만 식별하면 되므로 회원 리소스를 URI에 매핑하면 된다.
API URI 설계
리소스를 식별하고 URI 계층 구조를 활용해서 URI를 설계해보자.
- 회원 목록 조회 /members
- 회원 조회 /members/{id}
- 회원 등록 /members/{id}
- 회원 수정 /members/{id}
- 회원 삭제 /members/{id}
참고: 계층 구조상 상위를 컬렉션으로 보고 복수단어 사용을 권장한다.(member ➡️ members)
위처럼 URI는 리소스(개념)만 식별해야 한다. 리소스와 해당 리소스(회원)를 대상으로 하는 행위(조회, 등록, 삭제, 변경)를 분리해야 한다. 보통 리소스는 명사, 행위는 동사가 된다. 그럼 행위는 어떻게 구분해야 할까?
HTTP 메서드
주요 메서드
- GET: 리소스 조회
- POST: 요청 데이터 처리, 등록
- PUT: 리소스를 대체, 해당 리소스가 없으면 생성
- PATCH: 리소스 부분 변경
- DELETE: 리소스 삭제
기타 메서드
- HEAD: GET과 동일하지만 메시지 부분을 제외하고 상태 줄과 헤더만 반환한다.
- OPTIONS: 대상 리소스에 대한 통신 가능 옵션(메서드)을 설명한다.(주로 CORS에서 사용)
- CONNECT: 대상 리소스로 릭별되는 서버에 대한 터널을 설정한다.
- TRACE: 대산 리소스에 대한 경로를 따라 메시지 루프백 테스트를 수행한다.
GET
- GET은 리소스를 조회하는 메서드이다.
- 서버에 전달하고 싶은 데이터는 query(쿼리 파라미터, 쿼리 스트링)를 통해서 전달한다.
- 메시지 바디를 사용해서 데이터를 전달할 수 있지만 지원하지 않는 곳이 많아서 권장하지 않는다.
POST
- POST는 요청 데이터를 처리한다.
- 메시지 바디를 통해 서버로 요청 데이터를 전달한다.
- 서버는 요청 데이터를 처리한다.
- 메시지 바디를 통해 들어온 데이터를 처리하는 모든 기능을 수행한다.
- 주로 전달된 데이터로 신규 리소스를 등록하고 프로세스 처리에 사용한다.
- 리소스 URI에 POST 요청이 오면 요청 데이터를 어떻게 처리해야 할지 정해진 것이 없어서 리소스마다 따로 정해야 한다.
POST 정리
- 새 리소스 생성(등록)
- 서버가 아직 식별하지 않은 새 리소스를 생성한다.
- 요청 데이터 처리
- 단순히 데이터를 생성하거나 변경하는 것을 넘어서 프로세스를 처리해야 하는 경우
- ex) 주문에서 결제 완료 ➡️ 배달 시작 ➡️ 배달 완료처럼 단순히 값 변경을 넘어 프로세스의 상태가 변경되는 경우
- POST의 결과로 새로운 리소스가 생성되지 않을 수 있다.
- ex) POST /orders/{orderId}/start-delivery (컨트롤 URI)
- 단순히 데이터를 생성하거나 변경하는 것을 넘어서 프로세스를 처리해야 하는 경우
- 다른 메서드로 처리하기 애매한 경우
- ex) JSON으로 조회 데이터를 넘겨야 하는데 GET 메서드를 사용하기 어려운 경우
- 애매하면 POST를 사용한다.
PUT
- PUT은 리소스를 "완전히" 대체한다.
- 리소스가 있으면 대체, 리소스가 없으면 생성하며, 쉽게 말해서 덮어버린다고 생각하면 된다.
- name과 age 필드가 존재할 때, age 필드만 변경하게 되면 name 필드가 사라져버린다.
- POST와의 큰 차이점은 클라이언트가 리소스를 식별한다.
- POST는 /members만 하면 되지만 PUT은 members/100이라고 지정을 해주어야 한다.
PATCH
- PATCH는 리소스를 부분 변경한다.
- name과 age 필드가 존재할 경우 age 필드의 값만 변경해도 name 필드는 사라지지 않는다.
- PATCH를 지원하지 않는 서버가 있을 수 있다. 그런 경우에는 POST를 사용하면 된다.
DELETE
- DELETE는 리소스를 제거한다.
HTTP 메서드의 속성
안전(Safe)
- 호출해도 리소르를 변경하지 않는다.
- Q: 그래도 계속 호출해서 로그가 쌓여 장애가 발생하면 어떡하나요?
- A: 안전은 해당 리소스만 고려합니다. 그런 부분까지 고려하지 않습니다.
멱등(Idempotent)
- f(f(x)) = f(x)
- 멱등이란 몇 번을 호출해도 결과가 같은 것을 의미한다.
- 멱등 메서드
- GET: 몇 번을 조회해도 같은 결과가 조회된다.
- PUT: 결과를 대체한다. 같은 요청을 여러 번 해도 최종 결과는 같다.
- DELETE: 결과를 삭제한다. 같은 요청을 여러 번 해도 삭제된 결과는 똑같다.
- POST는 멱등이 아니다. 두 번 호출하면 같은 결제가 중복해서 발생할 수 있다.
- 재요청 중간에 다른 곳에러 리소스를 변경해버리면?
- user1: GET ➡️ username:A, age:20
- user2: PUT ➡️ username:A, age:30
- user1: GET ➡️ username:A, age:30
- user2의 영향으로 바뀐 데이터가 조회된다.
- 멱등은 외부 요인으로 중간에 리소스가 변경되는 것까지는 고려하지 않는다.
캐시가능(Cacheable)
- 응답 결과 리소스를 캐시해서 사용해도 될까?
- GET, HEAD, POST, PATCH는 캐시가 가능하다.
- 실제로는 GET, HEAD 정도만 캐시로 사용한다.
- POST, PATCH는 본문 내용까지 캐시 키로 고려해야 하는데 구현이 쉽지 않기 때문
🐣 출처: 인프런 김영한님 강의
이 글은 인프런의 김영한님 HTTP 웹 강의를 보고 작성한 글입니다.
강의를 들으면서 정리한 글이므로 틀린 내용이나 오타가 있을 수 있습니다.