[HTTP] HTTP 메서드
HTTP API를 만들어보자(설계 예시)
회원 정보와 관련된 CRUD 기능이 있는 API를 만들어야한다고 가정해보자. 회원 조회, 등록, 수정, 삭제에 대한 API URI를 설계해야하는데, 명명하는게 쉽지는 않다.
API를 설계할 때 가장 중요한 것은 리소스 식별이다. 리소스를 기준으로 설계해야 한다. 이 때, 회원을 등록, 수정, 조회하는 것이 리소스가 아니라, 회원 이라는 개념 자체가 리소스이다.
회원이라는 리소스만 URI에 맵핑하고, 등록, 수정, 삭제와 같은 행위는 HTTP 메소드를 통해 명시한다. HTTP 메서드는 클라이언트가 서버에 뭔가 요청을 할 때 기대하는 행위라고 이해하면 된다.
행위 기준 설계 | 리소스 기준 설계 | ||
회원 목록 조회 | /read-member-list | /members | GET |
회원 상세 조회 | /read-member-by-id | /members/{id} | GET |
회원 등록 | /create-member | /members/{id} | POST |
회원 수정 | /update-member | /members/{id} | PUT |
회원 삭제 | /delete-member | /members/{id} | DELETE |
HTTP 메서드 - 주요 메소드
1. GET
- 의미 : 리소스 조회
- 서버에 전달하고싶은 데이터는 query (쿼리 파라미터=쿼리스트링)에 담아 보낸다.
- [요청 데이터]
GET /search?q=hello&h1=ko HTTP/1.1
Host: www.google.com
- [요청 데이터]
- 최근 스펙에서는 메세지 바디에 데이터를 담아 보내는게 허용되어있지만, 지원하지 않는 서버가 많아 권장하지 않는다.
- 요청/응답 과정
- 클라이언트가 요청데이터를 GET 메시지를 만들어 서버로 전송한다.
- 서버는 이 메시지를 읽고, DB에서 데이터를 조회한다.
- 데이터를 json 혹은 다른 방식으로 만들어 메시지 바디에 넣고, 응답 메시지를 만들어 클라이언트에게 전달한다.
2. POST
- 의미 : 요청 데이터를 처리 (주로 등록에 사용)
- 메시지 바디를 통해 서버로 요청 데이터를 전달하고, 이 데이터를 처리하는 모든 기능을 수행한다.
- [요청 데이터]
POST /members HTTP/1.1
Content-Type: application/json
{
"username": "hello",
"age": 20
}
- [요청 데이터]
- 주로 전달된 데이터로 신규 리소스를 등록하거나, 프로세스 처리에 사용한다. 해당 프로세스에 대해서는 미리 약속이 필요하다.
- 요청/응답 과정
- /members 로 데이터가 들어오면, 서버가 그 데이터를 저장한다고 미리 약속된 상태
- 클라이언트가 /members 경로로 POST 메시지를 만들어 보낸다.
- 서버에서 메시지를 읽고, DB에 그 데이터를 저장한다. 이 때 신규 리소스 식별자가 생성된다.
- /members --> /member/100 : 100번이라는 신규 리소스 식별자가 생성된 것
- 응답 데이터를 만들어 클라이언트에게 전송한다.
- 신규 자원이 생성되면 보통 HTTP 201 created라고 보낸다. (200으로 보내도 된다.)
- 201로 보낼 땐 헤더에 신규 생성된 URI 경로와 등록된 데이터도 보내준다.
- [응답 데이터]
HTTP/1.1 201 Created
Content-Type: application/json
Content-Length: 34
Location: /members/100
{
"username": "hello",
"age": 20
}
- [응답 데이터]
- 컨트롤 URI 에서도 POST를 많이 쓴다. (실무에서 리소스만 가지고 URI를 다 설계할 수 없다.)
- 조회성 요청이지만query parameter에 json형태를 보내야한다면, 그 때에도 GET이 아니라 POST를 사용한다. (GET으로 올 때는 캐싱이 쉽지만, POST는 캐싱이 어렵기 때문에 가능하면 조회할 땐 GET을 쓰는게 유리하다.)
3. PUT
- 의미 : 리소스를 대체 (리소스가 없으면 생성, 있으면 덮어쓰기)
- [요청 데이터]
PUT /members/100 HTTP/1.1
Content-Type: application/json
{
"username": "bye",
"age": 30
}
- [요청 데이터]
- POST와 차이점은 클라이언트가 리소스 전체 경로를 구체적으로 알고 있다는 점이다. POST의 경우 서버에서 식별자를 몇 번으로 설정할 지 알 수 없다.
- 기존 리소스의 특정 컬럼(age) 값만 고치고 싶다고 메시지 바디에 { "age": 30 } 라고 보내면 원하는 결과를 얻을 수 없다. PUT은 리소스를 대체하는 것이기 때문에 "username" 값은 아예 날라가고, "age" 값만 있는 리소스로 대체되는 것이다. 이렇게 원하는 부분만 변경하고싶을 때에는 PATCH를 사용한다.
4. PATCH
- 의미 : 리소스 부분 변경 (이름을 바꾸거나 이런 특정 필드를 몇 개 바꿀 때 사용)
- [요청 데이터]
PATCH /members/100 HTTP/1.1
Content-Type: application/json
{
"age": 30
}
- [요청 데이터]
- PATCH가 지원되지 않는 서버가 간혹 있을 수 있는데, 이런 경우에는 POST를 사용하면 된다.
5. DELETE
- 의미 : 리소스 삭제
- [요청 데이터]
DELETE /members/100 HTTP/1.1
Host: www.google.com
- [요청 데이터]
HTTP 메서드 - 기타 메소드
1. HEAD
- 의미 : GET과 동일하지만 메시지 바디 부분을 제외하고, 상태 줄과 헤더만 반환
2. OPTIONS
- 의미 : 대상 리소스에 대한 통신 가능 옵션을 설명 (주로 CORS에서 사용)
3. CONNECT (거의 사용하지 않는다)
- 의미 : 대상 자원으로 식별되는 서버에 대한 터널을 설정
4. TRACE (거의 사용하지 않는다)
- 의미 : 대상 리소스에 대한 경로를 따라 메시지 루프백 테스트를 ㅅ ㅜ행
HTTP 메서드의 속성
1. 안전 (Safe Methods)
호출해도 리소스를 변경하지 않는다는 의미이다. GET은 단순히 조회만 하는 것이기 때문에 안전하고, 호출했을 때 데이터가 변경될 여지가 있는 POST, PUT, DELETE 등은 안전하지 않다.
GET 이라도 호출을 너무 많이 하면 서버에 부하가 걸리거나 로그가 쌓여 장애가 발생할 수 있다. 하지만 이런 것은 안전을 판단하는 기준에 포함되지 않는다. 리소스가 변경되지 않는 것만 고려한다.
2. 멱등 (Idempotent Methods)
f(f(x)) = f(x) 를 만족해야한다. 즉, 내가 동일한 요청을 한번 호출하던 여러번 호출하던 결과가 똑같다는 뜻이다. 중간에 다른 외부 요인으로 인해 중간에 리소스가 변경되는 것 까진느 고려하지 않는다.
GET은 여러번 조회해도 같은 결과가 조회된다. PUT은 결과를 대체하기 때문에, 같은 데이터를 여러번 대체해도 최종 결과는 같다. DELETE도 같은 리소스를 여러번 삭제했을 때 최종 결과는 동일하다.
POST는 여러번 호출하면 중복하여 데이터가 입력될 수 있고, 멱등이 아니다.
멱등한 경우에는 서버가 timeout등으로 정상 응답을 주지 못했을 때 클라이언트가 같은 요청을 다시 해도 되기 때문에, 자동복구 매커니즘을 타도록 설정해도 된다.
3. 캐시 가능 (Cacheable Methods)
응답 결과 리소스를 캐시해서 사용해도 되는가? GET, HEAD, POST, PATCH가 캐시 가능하다고 하지만, 실제로는 GET, HEAD 정도만 캐시로 사용한다. POST, PATCH는 본문 내용까지 캐시 키로 고려해야하는데, 구현이 쉽지 않기 때문이다.
*resource라는 표현이 2014년 스펙부터 representation이라는 명칭으로 바뀌었다.
더 공부해보자
- 컨트롤 URI
이 포스팅은 모든 개발자를 위한 HTTP 웹 기본 지식 강의를 수강하며 작성되었습니다.
모든 개발자를 위한 HTTP 웹 기본 지식 | 김영한 - 인프런
김영한 | 실무에 꼭 필요한 HTTP 핵심 기능과 올바른 HTTP API 설계 방법을 학습합니다., [사진] 📣 확인해주세요!본 강의는 자바 스프링 완전 정복 시리즈의 세 번째 강의입니다. 우아한형제들 최연
www.inflearn.com