HTTP 요청(GET, POST, PUT, FETCH, DELETE)과 멱등성을 이해해 보자
📌 서론
최근 조금 준비할 것이 생겨 글을 적지 못했다. 그래서 부랴부랴 글을 적으려고 고민을 하던 도중 이전에 세미나를 들으며 정리해 두었던 내용이 있는데 바로 이번 포스트에서 소개할 "HTTP요청에 대한 이해"다. 개인적으로 처음 들었을 때 "멱등성" 파트에서 멘붕을 당했다.
어? 이게 뭐야? 멱등성..? 이렇게 벙찔정도로 약간 충격이었다. 왜냐하면 "나는 API 개발만큼은 잘 알고 있어!"라고 생각하면서 개발해 왔고 주변의 질문에도 아는 것처럼 대답했었는데 막상 내부를 살짝이나마 조금 뜯어보니 제대로 알지 못했던 것이다.
그래서 이번 기회에 정리해 뒀던 내용을 종합해서 모아봤다. GET~DELETE까지의 요청과 그 사이사이 꼭 알아야만 하는 내용들을 정리했다. 깊게 파지는 않았으니 스쳐 지나가며 지식습득정도로만 봐줬으면 한다.
1. GET 메서드
데이터 조회
- GET 메서드는 주로 데이터를 조회할 때 사용된다. 이 메서드의 특징은 데이터를 URL의 쿼리 스트링으로 전송한다.
- 예를 들어, "http://example.com/api/users?name=John"와 같이, 조회하고자 하는 데이터(name=John)는 URL에 직접 포함된다.
- 중요한 점은, GET 메서드에서는 HTTP 메시지의 본문(Body)을 사용하지 않는다는 것이다.
보안과 예시
- GET 메서드의 한계는 보안 측면에 있다. URL에 데이터가 노출되므로, 민감한 정보를 전송하는 데는 적합하지 않다.
- 예를 들면, 사용자 조회 요청은 다음과 같다.
GET /api/users?name=John HTTP/1.1
Host: example.com
2. POST 메서드
안전한 데이터 전송
- POST 메서드는 데이터를 서버로 전송할 때 사용된다. 이 메서드의 핵심은 데이터를 HTTP 메시지의 본문(Body)에 포함시켜 전송하는 것이다. 이 방식은 민감한 정보 전송이나 새로운 리소스 생성(예: 사용자 등록, 글 작성)에 적합하다.
- POST 메서드는 데이터를 안전하게 전송할 수 있는 방법으로, JSON, XML, 폼 데이터 등 다양한 형식을 사용할 수 있다.
보안과 예시
- 보안 측면에서, POST는 데이터가 HTTP 메시지 본문에 포함되어 전송되기 때문에, GET보다 보안성이 높다.
- 예를 들어, 새로운 사용자를 생성하는 요청은 다음과 같다.
POST /api/users HTTP/1.1
Host: example.com
Content-Type: application/json
{
"name": "John",
"age": 30
}
📌 GET과 POST의 핵심 차이점
GET과 POST의 핵심 차이점은 데이터 전송 방식에 있다. GET은 데이터 조회에 최적화되어 있으며, 데이터가 URL에 노출되어 전송된다.
반면, POST는 데이터를 안전하게 서버로 전송하는 데 사용되며, 데이터가 HTTP 메시지의 본문에 포함되어 전송된다. 이러한 차이점은 각 메서드의 사용 상황을 결정하는 데 중요한 기준이 된다.
3. PUT 메서드
리소스 전체 교체
- PUT 메서드는 서버에 저장된 리소스를 완전히 새로운 데이터로 대체할 때 사용된다. 이 메서드의 핵심은 기존 리소스를 전체적으로 교체하는 것이다. 이를 위해서는 대체될 리소스의 전체 구조와 데이터를 알고 있어야 한다.
- 또한, PUT은 멱등한 연산으로 간주된다. 즉, 같은 PUT 요청을 여러 번 수행해도 서버 상태는 마지막 요청에 의해 결정된다.
예를 들면, 다음과 같이 사용자 정보를 업데이트하는 요청이 있을 수 있다.
PUT /api/users/123 HTTP/1.1
Host: example.com
Content-Type: application/json
{
"name": "John",
"age": 35,
"email": "john@example.com"
}
4. PATCH 메서드
리소스의 일부 수정
- 반면, PATCH 메서드는 리소스의 일부분만을 수정할 목적으로 사용된다. 이 메서드는 특정 필드만을 명시하여 변화를 주기 때문에, 전체 구조를 알지 못해도 특정 부분을 수정할 수 있다.
- PATCH의 멱등성은 구현 방식에 따라 달라질 수 있다. 일부 구현에서는 멱등할 수 있지만, 모든 경우에 그렇지는 않다.
예를 들어, 사용자의 나이만 변경하는 간단한 요청은 다음과 같이 될 수 있다.
PATCH /api/users/123 HTTP/1.1
Host: example.com
Content-Type: application/json
{
"age": 36
}
📌 PUT과 PATCH의 차이점
PUT과 PATCH의 주요 차이점은 리소스의 처리 방식에 있다. PUT은 전체 리소스를 새로운 데이터로 완전히 대체하는 데 사용되며, 멱등성을 가지고 있다.
반면, PATCH는 리소스의 일부분만 수정하는 데 사용되며, 멱등성 여부는 요청의 내용과 구현에 따라 달라질 수 있다. 이 두 메서드 모두 수정 작업에 사용되지만, PUT은 전체 리소스 교체에, PATCH는 부분 수정에 더 적합하다.
5. PUT과 PATCH 메서드의 멱등성 이해하기
HTTP 메서드 중 PUT과 PATCH는 멱등성(Idempotency)의 관점에서 자주 논의된다. 멱등성이란, 동일한 요청을 여러 번 수행해도 결과가 일관되게 유지되어야 한다는 원칙을 말한다. 이 원칙은 서버 상태에 대한 요청의 영향을 예측 가능하게 만든다.
PUT 메서드의 멱등성
- PUT 메서드는 멱등하다. 즉, 동일한 PUT 요청을 여러 번 수행해도 서버의 특정 리소스 상태는 마지막 요청의 상태로 결정된다.
예를 들어, 아래의 요청은 사용자 정보를 업데이트한다.
PUT /api/users/123 HTTP/1.1
Host: example.com
Content-Type: application/json
{
"name": "John",
"age": 35,
"email": "john@example.com"
}
- 이 요청을 여러 번 보내도, 사용자 123의 정보는 항상 동일하게 유지된다. 이전 요청들이 만든 결과와 동일하기 때문에, PUT은 멱등성을 만족한다.
PATCH 메서드의 멱등성 (멱등할 때)
- PATCH 메서드의 멱등성은 구현 방식에 따라 다를 수 있다. PATCH는 리소스의 일부만을 수정한다.
- 예를 들어, 사용자의 나이를 특정 값으로 설정하는 경우, 요청을 여러 번 수행해도 결과가 동일하게 유지된다. 이러한 요청은 멱등성을 만족한다.
PATCH /api/users/123 HTTP/1.1
Host: example.com
Content-Type: application/json
{
"age": 30
}
Spring MVC 코드 예시
- UserController는 PATCH 요청을 받아 UserService의 updateAge 메서드를 호출한다. updateAge 메서드는 사용자의 나이를 새로운 값으로 설정한다.
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@PatchMapping("/{id}")
public ResponseEntity<User> updateUserAge(@PathVariable Long id, @RequestBody Map<String, Integer> updates) {
User user = userService.updateAge(id, updates.get("age"));
return ResponseEntity.ok(user);
}
}
- 서비스 로직에 이 요청이 여러 번 들어와도 해당 사용자의 나이는 항상 30세로 설정된다. 결과가 동일하기 때문에, 이 연산은 멱등성을 만족한다고 할 수 있다.
@Service
public class UserService {
// 이 예시에서는 사용자 정보를 메모리에 저장한다고 가정합니다.
private Map<Long, User> users = new HashMap<>();
public User updateAge(Long id, Integer newAge) {
User user = users.get(id);
if (user != null && newAge != null) {
user.setAge(newAge);
}
return user;
}
}
PATCH 메서드의 멱등성 (멱등하지 않을 때)
- 사용자의 점수를 증가시키는 요청의 경우, 요청마다 결과가 달라질 수 있으므로 멱등하지 않다.
- 예를 들어, 아래의 요청을 여러 번 보내면 점수가 계속 증가한다.
PATCH /api/users/123 HTTP/1.1
Host: example.com
Content-Type: application/json
{
"increaseScoreBy": 10
}
Spring MVC 코드 예시
- 이 UserController는 클라이언트로부터 PATCH 요청을 받아 UserService의 increaseScore 메서드를 호출한다. 이 메서드는 사용자의 점수를 증가시킨다.
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@PatchMapping("/{id}")
public ResponseEntity<User> increaseUserScore(@PathVariable Long id, @RequestBody Map<String, Integer> updates) {
User user = userService.increaseScore(id, updates.get("increaseScoreBy"));
return ResponseEntity.ok(user);
}
}
- 만약 같은 PATCH 요청(increaseScoreBy: 10)을 여러 번 보내면, 서비스의 increaseScore 메서드는 매번 호출될 때마다 사용자의 점수를 10씩 증가시키므로, 이는 멱등하지 않은 연산이라고 할 수 있다. 요청을 반복할 때마다 최종 결과가 달라지기 때문이다.
@Service
public class UserService {
// 여기서는 간단한 예시를 위해 사용자 정보를 메모리에 저장한다고 가정합니다.
private Map<Long, User> users = new HashMap<>();
public User increaseScore(Long id, Integer increaseBy) {
User user = users.get(id);
if (user != null && increaseBy != null) {
user.setScore(user.getScore() + increaseBy);
}
return user;
}
}
📌 요약
내용을 정리해 보면 PUT 메서드는 리소스 전체를 교체하며 멱등성을 가진다.
반면 PATCH 메서드의 멱등성은 요청의 성격과 구현에 따라 다르다. 일부 요청은 멱등할 수 있으나, 모든 PATCH 요청이 멱등하다고 볼 수는 없다.
6. DELETE 메서드
파일 제거
- 이 메서드는 특정 사용자를 데이터베이스에서 삭제하거나 서버에서 파일을 제거할 때 주로 사용된다. DELETE 메서드의 특징은 대상 리소스의 URI를 통해 어떤 데이터를 삭제할지 지정한다는 것이다.
- 예를 들어, "http://example.com/api/users/123"라는 URL은 ID가 123인 사용자를 삭제하겠다는 의미를 담고 있다.
본문(Body) 사용에 관한 표준
- 이 메서드를 쓸 때 중요한 것 중 하나는 HTTP 스펙상 DELETE 요청은 일반적으로 본문(Body)을 포함하지 않는다는 점이다. 왜냐하면 모든 필요한 정보가 URI를 통해 전달되기 때문이다.
보안
- 보안 측면에서 DELETE 메서드는 URL에 데이터가 노출되지만, 대부분의 경우 리소스의 식별자(ID)만 노출되니 민감한 정보가 노출될 위험은 낮다. 하지만 안전한 통신을 위해서 HTTPS를 사용하는 게 좋다. 특히 DELETE 요청처럼 보안적으로 민감한 작업을 할 때는 사용자가 적절한 권한을 갖고 있는지 확인하는 게 중요하다.
- 권한 검증은 보통 HTTP 요청의 Authorization 헤더를 통해 이루어진다. 여기에는 인증 토큰이 포함되어 있고, 서버는 이 토큰을 분석해서 요청자의 권한을 확인한다. 예를 들어 DELETE 요청을 보낼 때는 다음과 같이 작성한다.
DELETE /api/users/123 HTTP/1.1
Host: example.com
- 요청을 작성할 때, 예를 들어 DELETE "/api/users/123 HTTP/1.1"이라고 쓰는 것은 표준 HTTP 프로토콜을 사용한다는 것을 의미한다. 여기서 "HTTP/1.1"은 HTTP 프로토콜의 버전을 나타낸다.
📌 요청 라인에는 HTTP라고 적혀있는데? HTTPS가 아니라?
HTTPS를 사용한다는 것은, 클라이언트와 서버 간의 통신이 암호화된 연결을 통해 이루어진다는 것을 의미한다. 이는 요청 라인에 직접 "HTTPS/1.1" 이렇게 적어주는 것이 아니라, 서버 설정과 클라이언트 구성을 통해 이루어진다는 의미다. 즉, 서버와의 연결이 HTTPS로 설정되어 있으면, 이 요청과 그에 대한 응답은 자동으로 암호화되어 전송된다.
7. 추가설명: 수정 (PUT, PATCH)과 권한 검증
PUT과 PATCH 메서드는 서버에 있는 데이터를 수정하기 위해 사용된다.
PUT은 전체 리소스를 대체하는 데 사용되고, PATCH는 리소스의 일부분만을 변경하는 데 사용된다.
요청 본문
- 이러한 요청들은 변경될 데이터를 HTTP 요청의 본문(Body)에 포함시킨다. 예를 들어, "article/update/{id}" 경로는 특정 아티클의 ID에 해당하는 부분을 수정하려 할 때 사용될 수 있다.
"article/update/{id}"
권한 정보 제외
- 요청 본문에는 사용자 식별자나 권한 정보를 포함해서는 안 된다. 이런 정보는 요청 본문보다는 HTTP 헤더를 통해 전송되어야 한다.
권한 검증
- 권한 검증은 서버 측에서 이루어진다. 스프링 시큐리티 같은 인증 미들웨어를 사용하여 이루어지는데, 이 미들웨어는 Authorization 헤더에 포함된 토큰을 분석하여 요청자의 신원과 권한을 확인한다.
📌 결론
DELETE 요청과 수정(UPDATE) 요청 모두 권한 검증이 필수적이다. 이는 서버의 리소스를 안전하게 보호하고, 사용자의 권한을 올바르게 관리하기 위해서 필요하다.
서버 측에서는 효과적인 보안 메커니즘을 구현해야 하며, 이는 인증과 권한 검증을 포함해야 한다. 스프링 시큐리티와 같은 도구를 사용해서 보다 편하게 구현할 수 있다. (나는 실제로 이렇게 사이드 프로젝트에서 하고 있다.😎)
이러한 개념들은 http서버 구현과 이어진다고 생각한다. 시간이 된다면 아래의 글도 한번 보는것을 추천한다.🤩
'기타 > WEB, DB, GIT' 카테고리의 다른 글
주니어 개발자의 API 이해하기 (4) | 2023.12.20 |
---|---|
[SQL] 쿼리 인젝션이란? (0) | 2023.11.21 |
Jenkins 깃허브 훅 설정 - GitHub hook trigger for GITScm Polling 설정하기 (0) | 2023.10.26 |
Github Access Token발급받는 방법 (2) | 2023.10.26 |
IndexedDB: CSR 데이터베이스 (0) | 2023.10.20 |