✍ HTTP 메서드 종류
HTTP 프로토콜에서 자주 사용되는 HTTP request method의 종류는 다음과 같습니다.
- GET : 리소스 조회. GET 메서드는 데이터를 가져올때만 사용.
- POST : 서버로 데이터를 전송한다. 새로운 리소스를 생성(등록)할 때 주로 사용.
- PUT : 요청 데이터를 사용하여 새로운 리소스를 생성하거나, 대상 리소스를 나타내는 데이터를 대체.
- PATCH : 리소스를 부분적으로 변경.
- DELETE : 리소스 삭제.
이 외에 이런 메소드들도 있습니다.
- HEAD : GET 메서드와 동일하지만, 상태 줄과 헤더만 반환받음.
- CONNECT : 요청한 리소스에 대해 양방향 연결을 시작하는 메소드. 터널을 열기 위해 사용.
- OPTIONS : 목표 리소스와의 통신 옵션을 설명하기 위해 사용됨. (주로 CORS에서 사용)
- TRACE : 대상 리소스에 대한 경로를 따라 메시지 루프백 테스트를 수행.
💦 HTTP 메서드 속성
각 HTTP 메서드마다 용도와 특징이 다릅니다. 메서드 속성은 이러한 특징을 알 수 있는 지표라고 볼 수 있습니다.
메서드 속성의 종류는 크게 다음과 같습니다.
- 안전 (Safe Methods)
- 멱등 (Idempotent Methods)
- 캐시 가능 (Cacheable Methods)
- 요청에 본문(Body) 존재
- 성공 응답에 본문(Body) 존재
안전 (Safe)
안전(Safe)은 호출해도 리소스를 변경하지 않는 메서드 속성입니다. 즉, 데이터의 변경이 일어나지 않는다는 뜻입니다. GET 메서드는 단순히 데이터를 가져올때 사용하는데, 이러한 GET 같은 메서드를 안전(safe) 하다고 합니다.
멱등 (Idempotent)
몇 번을 호출하든 최종적인 결과는 똑같은 메서드 속성입니다. 데이터를 가져오거나(GET), 삭제하거나(DELETE), 완전히 대체하는(PUT) 작업은 몇 번이 수행되건 상관없이 결과는 같습니다. 특정 데이터를 조회하는것의 결과는 조회하는 것이고, 특정 데이터를 삭제하는 것의 결과는 그 데이터가 삭제 된 것입니다.
하지만, POST의 경우는 다릅니다. POST 메서드로 결제를 수행했다고 가정해보겠습니다. 해당 POST 메소드가 두 번 호출된다면 결제가 중복해서 발생할 수 있습니다. 사용자의 돈이나 제품의 수량같은 데이터가 계속해서 달라지겠죠. 따라서, 이러한 메소드는 멱등하지 않은 것입니다.
이러한 속성은 서버의 문제로 클라이언트가 같은 요청을 다시해도 되는가? 에 대한 판단 근거가 될 수 있습니다.
캐시 가능 (Cacheable)
응답 결과 리소스를 캐시해서 사용해도 되는지에 대한 속성입니다. GET과 HEAD, POST, PATCH 메소드가 이 속성을 가집니다. 일반적으로 GET, HEAD 정도만 캐시로 사용합니다.
요청 / 응답에 Body 존재
요청이나 응답시 데이터를 Message Body에 담아 보내는지, 아닌지에 대한 속성입니다.
아래는 HTTP method에 따른 속성을 정리한 표입니다.
🌟 주요 HTTP 메서드 특징
📌 GET → 리소스 조회
GET은 리소스를 조회하는 메서드입니다. 서버에 전달하고 싶은 데이터는 query(쿼리 파라미터, 쿼리 스트링)을 통해서 전달합니다.
- GET 메서드 요청 예시
GET /search?q=hello&hl=ko HTTP/1.1
Host: www.google.com
참고 : 메시지 바디를 통해서 데이터를 전달할 수 있지만, 지원하지 않는 곳이 많아서 권장하지 않음.
GET 데이터 전송 방식
- query (쿼리 파라미터)
쿼리 파라미터는 GET 메서드로 요청할 때 클라이언트에서 서버로 데이터를 전송하기위해 사용하는 데이터 전송 방식입니다. 위 GET 요청 예시에서 /serch 라는 리소스 뒤에 따라오는 q=hello&hl=ko 문자가 바로 쿼리 파라미터입니다.
쿼리 파라미터는 리소스 경로 뒤에 '?' 문자를 붙여 시작하여, Key-Value 형태로 데이터를 전송합니다. 추가적인 데이터는 '&' 문자로 이어줍니다. 예시로, 서버에서는 쿼리 파라미터로 넘어온 데이터에서 q(KEY) 를 통해 hello(VALUE)를 가져올 수 있게 되는 것이죠.
쿼리 파라미터로 데이터를 전송하게되면 URL에 데이터가 그대로 노출되기때문에 보안에 취약합니다. 따라서, 보통 쿼리 파라미터로 데이터를 전송할 땐 보안에 민감하지 않은 내용을 포함시킵니다.
📌 POST → 요청 데이터 처리
POST는 요청 데이터를 처리하는 메서드입니다. 주로 전달된 데이터로 신규 리소스를 등록하거나, 프로세스 처리에 사용합니다. 사실 POST 메서드는 등록뿐만 아니라 데이터를 처리하는 모든 기능을 수행할 수 있습니다. 요청 데이터를 어떻게 처리할지 서버에서 리소스마다 따로 지정해야 하기 때문입니다. POST에 대한 동작은 서버가 정하기 나름인 것입니다.
POST 메서드는 예를 들어 다음과 같은 기능에 사용됩니다.
- 회원가입을 통해 새로운 사용자 추가하기.
- 게시판, 뉴스 그룹, 메일링 리스트나 이와 유사한 시스템에 글 올리기
- 신규 주문 생성.
- 한 문서 끝에 내용 추가하기.
- 양식 전송 결과 등 데이터 블록을 데이터 처리 프로세스에 보내기
정리하자면 새로운 데이터를 등록하거나 요청 데이터를 처리 할 때, 또는 다른 메서드로 처리하기 애매한 경우 POST 메서드를 사용하면 됩니다.
- POST 메서드 요청 예시
POST /members HTTP/1.1
Content-Type: application/json
{
"username": "hello",
"age": 20
}
- HTTP 메시지에서 공백 아래에 오는 데이터가 Message Body 입니다. POST 메서드에서는 Message Body에 데이터를 담아 보냅니다. 서버에서는 신규 리소스를 등록하고 생성된 리소스의 경로를 응답데이터로 반환합니다. EX) /member/100
POST 데이터 전송 방식
서버에 전달하고 싶은 데이터는 메시지 바디를 통해 서버로 요청 데이터를 전달합니다. 서버에서는 이 요청 데이터를 처리하는 동작을 수행하게 됩니다.
📌 PUT
PUT는 리소스를 완전히 대체하는 메서드입니다. 요청 데이터에 해당하는 리소스가 존재하면 대체하고 없다면 새로 생성합니다. 쉽게 이야기해서 폴더에 파일 붙여넣기 하는 것 처럼 덮어버린다고 생각하시면 됩니다.
중요한 점은 요청시 클라이언트가 리소스를 알고있다는 점입니다. 클라이언트가 PUT 메서드로 요청을 보낼 때 리소스의 경로를 알고 URL을 지정합니다. 어떤 데이터를 대체할지를 알아야 요청을 보낼 수 있으므로 당연합니다. POST 메소드는 클라이언트가 등록될 리소스의 경로를 모른다는 점에서 차이가 있습니다.
- PUT 메서드 요청 예시
PUT /members/100 HTTP/1.1
Content-Type: application/json
{
"username": "hello",
"age": 20
}
PUT 데이터 전송 방식
서버에 전달하고 싶은 데이터는 메시지 바디를 통해 서버로 요청 데이터를 전달합니다. 서버에서는 /member/100 이라는 경로의 데이터를 요청의 데이터로 완전히 대체하거나 새로 등록합니다. 따라서, PUT 메서드는 몇번을 수행하더라도 결과가 같습니다. (멱등성)
- 완전히 대체한다는 의미는 기존 데이터를 삭제 후 새로 등록하는 것과 같습니다. 따라서 기존 데이터의 손실이 있을 수 있습니다.
📌 PATCH
PATCH는 리소스를 부분적으로 대체하는 메서드입니다. 기능적으로는 PUT과 유사하지만 PUT은 기존 데이터를 완전히 대체 하고, PATCH는 요청 데이터만 부분적으로 변경합니다.
- PATCH 메서드 요청 예시
PATCH /members/100 HTTP/1.1
Content-Type: application/json
{
"age": 50
}
- POST, PUT과 마찬가지로 데이터를 Message Body를 통해 전송합니다.
🎯 PUT 과 PATCH 의 차이점
예를 들어 member/100 리소스에 "username" : "Lee", "age" : 20 이라는 데이터가 저장되어있다고 가정해보겠습니다. 위와 같이 PATCH 메서드로 해당 리소스 경로에 "age" : 50 데이터를 보내면 "age" 필드의 값만 변경되기 때문에 최종적으로 "username" : "Lee", "age" : 50 의 데이터를 가지게 됩니다.
반면 PUT 메서드는 방금과 같은 상황에서 기존 리소스를 완전히 대체하기 때문에 "age" : 50 의 데이터만 남게 됩니다. 기존 "username" 필드는 삭제된 것입니다.
- 예시에서 요청에 대한 최종 데이터
- PUT : [기존] "username" : "Lee", "age" : 20 → [요청 후] "age" : 50
- PATCH : [기존] "username" : "Lee", "age" : 20 → [요청 후] "username" : "Lee", "age" : 50
📌 DELETE
DELETE는 리소스를 제거하는 메서드입니다. 요청 리소스 경로의 데이터를 삭제합니다.
- DELETE 메서드 요청 예시
DELETE /members/100 HTTP/1.1
Host: localhost:8080
- /member/100 경로의 리소스를 제거합니다.
정리
HTTP 메서드의 종류는 다음과 같으며 상황에 따라 유연하게 사용할 수 있습니다.
- GET : 리소스 조회. GET 메서드는 데이터를 가져올때만 사용.
- POST : 서버로 데이터를 전송한다. 새로운 리소스를 생성(등록)할 때 주로 사용.
- PUT : 요청 데이터를 사용하여 새로운 리소스를 생성하거나, 대상 리소스를 나타내는 데이터를 대체.
- PATCH : 리소스를 부분적으로 변경.
- DELETE : 리소스 삭제.
- HEAD : GET 메서드와 동일하지만, 상태 줄과 헤더만 반환받음.
- CONNECT : 요청한 리소스에 대해 양방향 연결을 시작하는 메소드. 터널을 열기 위해 사용.
- OPTIONS : 목표 리소스와의 통신 옵션을 설명하기 위해 사용됨. (주로 CORS에서 사용)
- TRACE : 대상 리소스에 대한 경로를 따라 메시지 루프백 테스트를 수행.
좋은 API URL 설계❗🧨
여기서 오해할 수 있는 부분이 "HTTP 메서드 자체에는 기능이 없다"는 점입니다. 예를 들어, DELETE로 클라이언트에서 서버로 리소스 경로를 보내주면 자동으로 해당 데이터가 삭제되는 것이 아닙니다. 개발자가 그렇게 동작하도록 구현해주어야 하죠. 요청에 대한 동작은 개발자가 구현한대로 이루어집니다. 서버에서 DELETE 메서드 요청을 통해 신규 리소스가 생성되게 구현하면 그렇게 동작하고, 반대로 POST 메서드 요청을 통해 리소스를 삭제하게 만들수도 있습니다.
그럼 HTTP 메서드는 왜 필요할까요? 바로 리소스(자원)와 행위를 분리하기 위해서입니다.
좋은 API URL 설계는 리소스와 행위가 분리되어있어야 합니다. 즉, URL에 행위가 포함되어있으면 좋은 설계가 아니라는 뜻입니다. 예를 들어 회원 정보 관리 API URL를 설계한다고 가정해보겠습니다.
- 회원 목록 조회 : /read-member-list
- 회원 조회 : /read-member-by-id
- 회원 등록 : /create-member
- 회원 수정 : /update-member
- 회원 삭제 : /delete-member
다음과 같이 URL에 리소스(자원)와 행위가 포함되어있는 것 보다,
- 회원 목록 조회 : /members - GET
- 회원 조회 : /members/{id} - GET
- 회원 등록 : /members/{id} - POST
- 회원 수정 : /members/{id} - PATCH & PUT
- 회원 삭제 : /members/{id} - DELETE
위의 URL 처럼 리소스만 깔끔하게 보여지고 행위는 HTTP method로 구분하게끔 설계하는 것이 유지보수측면에서 훨씬 유리합니다. 이러한 URL 설계에 대한 더 많은 설명은 'REST api'에 대한 내용을 찾아보시면 됩니다.
Reference
https://developer.mozilla.org/ko/docs/Web/HTTP
https://www.inflearn.com/course/http-%EC%9B%B9-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC