이론 정리

HTTP methods(멱등성, safe, post requestbody 검색, patch-put차이 등등..)

철매존 2023. 1. 8. 03:45
728x90

먼저 글을 시작하기 전에 몇가지 내용을 설명하려 한다.

Http methods가 뭔데

  • 브라우저가 서버로 데이터를 전달하는 방법이다.
  • 보통 이는 request header부분에 명시된다.

멱등성

멱등성이란, 여러 번 연산을 수행해도 동일한 결과를 보장하는 성질을 뜻한다.
이게 수학적으로 보면

f(f(x)) = f(x) 인 경우 멱등법칙을 만족한다는 것이다.

Safe

Safe Methods인지 아닌지를 판단하는 것으로, 서버의 상태를 변경시키지 않는 HTTP 메서드들을 뜻한다.
말하자면 해당 메서드가 실행되었을 때에 상태가 변경되는지를 의미한다.

REST Api

알다시피 REST api에서 우리는 get, post, put, patch, delete, HEAD, OPTIONS 와 같은 여러 메소드를 사용한다.

서버에 다음과 같은 Table이 있다고 가정하고 하나씩 확인해 보자.

Table이름 : human

ID Name State IQ
1 RyooChan Handsome 200
2 KingChan Smart 200

get에 대해서

Get은 보통 READ에 사용한다.
즉 서버에서 데이터를 읽어올 때에 사용하는 메소드라는 것이다. (Read)

서버에서 만약 human테이블의 1번 데이터를 가져온다고 가정해 보자.

아마 결과로는

ID:1, Name:RyooChan, State:Handsome, ID:200

의 데이터들이 return될 것이다.

만약 human/1을 1000을 수행한다고 해서 결과값이 바뀔까? 당연히 아니다. (멱등성O)

그리고 해당 메서드를 수행한다고 서버나 데이터가 변화하지는 않는다. (safe하다)

따라서

  • get은
    • 데이터를 읽어올 때에 사용된다.
    • 멱등성을 만족한다.
    • Safe-method이다.

고 볼 수 있을 것이다.

post

post는 보통 create에 사용한다. (근데 request를 통한 검색을 할 때에도 post를 쓰기 때문에 꼭 create에 쓰는건 아니다.)
일단은 그래도 create를 한다고 가정한다. (create)

서버에

Name : GodChan
State : Kind 
IQ : 200

라는 데이터를 입력해 주기 위해 post를 사용한다 생각하자.
이거를 1번 보내준다면?

ID Name State IQ
1 RyooChan Handsome 200
2 KingChan Smart 200
3 GodChan Kind 200

가 될 것이다.
근데 만약 이걸 997번 더 보내준다 생각해 보자

ID Name State IQ
1 RyooChan Handsome 200
2 KingChan Smart 200
3 GodChan Kind 200
... ... ... ...
1000 GodChan Kind 200

이렇게, 데이터가 바뀐것을 확인할 수 있다.
즉 한번 보내는거랑 여러번 보내는 것의 결과가 다르다. (멱등성 X)

그리고 당연하겠지만 이건 수행될 때마다 서버나 데이터의 상태를 변경시킨다. (safe하지 않다.) 따라서

  • post는
    • data 삽입(create)에 사용된다.
    • 멱등성을 만족하지 않는다.
    • safe하지 않은 method이다.

라는 것을 알 수 있다.

Post를 통한 검색?? - RequestBody를 쓸 때 왜 POST를 통해 검색하지?

위에서 requestBody를 사용하는 경우 Post를 사용하여서 검색을 한다고 한다.
이게 왜일까??

보통 우리는 검색을 할 때에 Get을 통해서 진행한다.
참고로 예전에는 Get에는 RequestBody를 사용할 수 없었는데, 요즘은 Get에서도 requestBody를 사용할 수도 있다.

그런데 requestBody를 사용해서 검색할 때에는 Post메서드를 사용해서 검색하는 것이 권장된다.

그 이유는 Get의 경우는 기본적으로 validation을 요구하지 않기 때문이다.
근데 반대로 RequestBody를 통해 받아온 데이터의 경우는 기본적으로 검증해야 한다.

그러니까

  • Get
    • 기본적으로 들어오는 파라미터를 검증하지 않음
  • RequestBody
    • 얘는 기본적으로 사용할 때에 검증하는게 좋음
  • Post
    • 기본적으로 들어오는 파라미터를 검증함.

오... 그럼 RequestBody를 사용하는 경우는 Post를 사용하는 것이 좋겠네??
가 된 것이다.

정리하자면

  • RequestBody를 사용한 Read를 사용할 때에는 Get이 아닌 Post를 사용하는 것이 표준이다.
    • 이는 Validation check를 조금 더 예쁘게 지킬 수 있기 때문이다.

사실 이외에도 get의 경우는 서버로그에 데이터가 남는다거나, post를 사용한 마스킹 여부라거나 등등...다양한 이유가 있다.

Put

put은 보통 data의 수정에 사용된다.
근데 중요한건 이거는 데이터 전체를 변경할 때에 사용하는 메서드라는 것이다.

만약 서버에
1번 데이터의 Statevery Handsome 으로 바꾸어 준다고 가정해 보자.

그 결과로 데이터는

ID Name State IQ
1 null very Handsome null
2 KingChan Smart 200
3 GodChan Kind 200
... ... ... ...
1000 GodChan Kind 200

이 될것이다.

보다시피 변경하기로 한 State데이터 외에는 null이 된것을 확인할 수 있다. (ID는 PK이므로 당연히 변경요청을 할때에 보내주었음.)

그렇기 때문에 PUT을 사용할 거라면 모든 데이터를 알아와서 넣어야 한다는 것이다. (참고로 이는 serverside에서 찾아와 넣어줘도 되기 때문에 client가 반드시 모든 데이터를 알 필요는 없다.)

예를 들자면

  • 1번 데이터의
    • Name : RyooChan
    • State : Very Handsome
    • IQ : 200

으로 변경한다면

ID Name State IQ
1 RyooChan Very Handsome 200
2 KingChan Smart 200
3 GodChan Kind 200
... ... ... ...
1000 GodChan Kind 200

이 될 것이다.

이 Put메서드는 그래서 사실 변경의 의미라기보다는

기존 데이터를 가져온 데이터로 바꿔 넣어 준다.

는 것으로 이해하면 좋을 것이다.

그리고 이 메서드를 1000번 실행해도 1번 데이터는 아무런 변경이 없다.
따라서 아무리 많은 PUT을 수행해도 동일한 데이터들이 유지될 것이다. (멱등성 O)

다만, Put메서드를 수행하면 데이터와 서버 상태가 변경된다. (safe하지 않다.)

없는 데이터의 경우는?

Put메서드는 요청한 자원이 없으면 자원을 생성한다.

만약

  • 1001번 데이터의
    • Name : RyooChan
    • State : Very Handsome
    • IQ : 200

의 put작업을 수행해 준다고 생각해 보자.
근데 위의 데이터를 보면 알겠지만 여기는 1001번 데이터가 없다.

Put의 경우 이 때에 아예 새로운 데이터를 만들어 준다.

ID Name State IQ
1 RyooChan Very Handsome 200
2 KingChan Smart 200
3 GodChan Kind 200
... ... ... ...
1000 GodChan Kind 200
1001 RyooChan Very Handsome 200

요런 식으로

참고로, 이 다음에 아무리 put을 계속 해도 1001의 변경 결과값은 똑같고, 이는 POST와는 다르게 멱등성을 유지한다는 것을 알 수 있다.

따라서

  • Put은
    • 데이터를 새롭게 넣어줄 때에 사용된다.
      • 전체 데이터를 변경하도록 한다.
        • 이 때문에 클라이언트 측에서 서버의 모든 데이터를 아는 상황에서 쓴다고 가정하는 것이 좋다.
      • 데이터가 없는 경우는 하나 만들어 준다.
    • 멱등성을 만족한다.
    • safe하지 않은 method이다.

라는 것을 알 수 있다.

Patch

patch는 보통 데이터 일부의 변경에 사용된다.
중요한 것은 데이터의 값을 일부만 변경해 준다는 것이다.

이는 Put의 '기존 데이터를 바꾸어 넣어 주는' 것과는 다른데, 한번 보자.

ID Name State IQ
1 RyooChan Very Handsome 200
2 KingChan Smart 200
3 GodChan Kind 200
... ... ... ...
1000 GodChan Kind 200
1001 RyooChan Very Handsome 200

여기서

만약 서버에
1번 데이터의 Stategenius 으로 바꾸어 준다고 가정해 보자.

ID Name State IQ
1 RyooChan genius 200
2 KingChan Smart 200
3 GodChan Kind 200
... ... ... ...
1000 GodChan Kind 200
1001 RyooChan Very Handsome 200

이렇게 된다.
이는 put과는 좀 다른데, 원하는 데이터만 변경되는 것을 알 수 있다.

없는 데이터의 경우는?

patch는 그냥 이 경우 에러를 보내준다.

만약 서버에
1002번 데이터의 Stategenius 으로 바꾸어 줘!!

라는 데이터를 보내면

-> 그런건 없는데??
-> Error!!!

가 된다.

Patch의 멱등성

위의 예시를 보면

  • 변경
    • 데이터가 변경됨 -> 계속 같은 데이터로 변경된다.
  • 없는 경우
    • 에러!!

가 계속해서 나오기 때문에 patch도 일견 멱등이라고 생각할 수 있다.
사실 위의 두 경우는 멱등이 많다.

근데 patch는 일부분을 변경하는 것이기 때문에 이런것도 가능하다.

  • 1번 데이터의
    • IQ에
      • 더하기 연산을 해줘
      • 10만큼

이런 요청을 보낼 수 있다. 예를 들면

patch/1

{
"operation" : "add"
, "IQ" : "10"
}

이런 RequestBody를 보내는 식이다.
그러면 이걸 1번 하면

ID Name State IQ
1 RyooChan Very Handsome 210

이고 여기서 추가로 3번 더하면

ID Name State IQ
1 RyooChan Very Handsome 225

가 나올 것이다.
이는 멱등성이 유지되지 않는다고 할 수 있다.

그리고 patch는 safe하지 않다. 서버와 데이터 상태가 변경되기 때문이다.

따라서 정리하자면

  • patch는
    • 데이터를 변경해 줄 때에 사용한다.
      • 변경 로직을 짜줄수도 있다.
      • 데이터가 없는 그냥 에러
    • 멱등성을 만족하지 않는다.
    • safe하지 않은 method이다.

Put vs Patch

여기서 보면 왠지 Patch는 일부분만 변경하면 되고 Put은 전체를 변경해야 되니까 Patch가 더 좋아 보인다.

근데 사실 써보면 Put은 자주 쓰는데 Patch를 쓰는 경우는 잘 없다.
이거는 왜일까??

전지적 java개발자의 관점에서 보자면 이 이유는 ORM이 put에 더 알맞기 때문이라고 생각한다.

이거를 보고 오면 좀 편할것같은데 보통 JPA를 써서 update를 할 때에는 dirty check를 사용해서 진행한다.

이 로직은

  1. 데이터를 읽어옴
  2. 그 데이터에서 입력된 데이터의 일부분을 바꿔줌
  3. 이 데이터가 변경됨.

이다.

이는 기존의 데이터를 가져오고, 데이터를 넣어준 다음 그걸 다시 입력함. 과 같은 느낌이다.

그니까 put을 사용하면

  1. 데이터를 읽어옴
  2. 변경할 데이터는 변경하려는 값으로 넣음
  3. 다른 데이터는 기존 값으로 넣음
  4. 그렇게 들어감

이고,

근데 patch를 보면 하나하나씩 들어오는 값들을 받아서, 이것들로 변경하는 로직이 필요할 것이다.

  • Name 변경
  • State 변경
  • IQ 변경

등등에 대한 변경 로직을 하나하나 설정해 줄 필요가 굳이 있나...? 싶을 것이다.
그게 아니어도 ORM의 dirty check를 쓰는 로직 자체가 PUT과 훨씬 가깝다.

그래서 patch보다 put이 많이 쓰이는 것이라고 생각한다.

delete

delete는 이름 그대로 삭제에 사용된다.

말 그대로

ID Name State IQ
1 RyooChan genius 200
2 KingChan Smart 200
3 GodChan Kind 200
... ... ... ...
1000 GodChan Kind 200
1001 RyooChan Very Handsome 200

여기서 1001번 데이터를 삭제하려고 하면

ID Name State IQ
1 RyooChan genius 200
2 KingChan Smart 200
3 GodChan Kind 200
... ... ... ...
1000 GodChan Kind 200

이렇게 삭제되고

한번 더 삭제하려고 하면 에러가 난다.

  • delete는
    • 데이터를 삭제할 때에 사용된다.
    • 멱등성을 만족한다.
    • Safe-method가 아니다.

head

리소스의 검색에서 "응답 헤더부분만 요청하는" 메서드이다.
즉, body가 없거나 이를 무시한다는 것이다.
대체 이딴걸 왜 쓰냐 생각할 수 있지만

헤더가 온다는 것은 여기 포함된 것들이 온다는 것인데, 거기에 Content-Length같은게 포함된다.
이 Content-length는 resource의 양을 파악하는데 사용되는데, 실제로 resource가 오는것은 아니므로 많은 데이터가 온다고 가정하면 성능 자체는 이게 빠르다.

그래서 이제

  • 캐시된 데이터가 변경되었나?
  • 지금 정보의 validation check
  • 이 유저가 들어갈 수 있는 유저가 맞는가?

등등처럼

  • 성능이 중요하거나
  • true/false처럼 http response만으로 파악 가능한 데이터를 요구하거나

등등의 상황에 사용할 수 있다고 한다.

이것도 검색용이라 멱등성이 유지되고, 안전한 메서드이다.

  • head는
    • 응답 헤더부분 확인에 사용된다.
    • 멱등성을 만족한다.
    • Safe-method이다.

options

이거는 preflight이다.
option 메서드는 "서버와 브라우저간의 통신 옵션 확인"에 사용된다.

즉, 어떤 메서드, content type 등을 지원하는지를 확인할 때 쓰인다.

예를 들어 PUT 메서드의 경우는 다양한 정보를 포함하고 있다.
그리고 이 정보가 많으면 좀 무겁다...

근데 만약에 나는 PUT으로 보냈는데 서버에서는 PUT을 안받는 경우, 쓸데없이 그냥 큰 데이터를 날리게 된 것이다.

그래서 이런 큰 데이터를 날리기 전에 미리 보내도 되는지 확인하기 위해 사용하는 메서드이다.
즉, 더 효율적인 통신을 위해 사용하는 메서드이다.

  • options는
    • preflight로, 서버 요청 가능 여부를 확인한다.
    • 멱등성을 만족한다.
    • Safe-method이다.

options 이친구 문제아임

preflight옵션이긴 한데 이게 좀 말이 많다.

  • 클라이언트 서버와 백엔드 서버가 서로 다른 경우(CORS) get, head, post를 제외한 모든 메서드 전송 이전에 options전송 요청됨.
    • 굳이 할 필요가 없는데도 보내짐
      • 이것도 성능에 문제가 생길 수 있다.
  • 사용 가능한 method를 알려준다.
    • 괜히 보안에 문제가 생길 수 있음

그래서 options를 안쓰기 위해 그냥 get이랑 post를 통해 모든 요청을 처리하는 경우도 있다고 한다...

정리

http 용도 멱등성 안전성
get 주로 검색용 멱등함 안전함
post 주로 생성용(requestBody쓸때 검색으로 쓰이기도함) 멱등하지 않음 안전하지 않음
put 주로 변경용(전체) 멱등함 안전하지 않음
patch 주로 변경용(일부) 멱등하지 않음 안전하지 않음
delete 주로 삭제용 멱등함 안전하지 않음
headers 주로 검색용(특별한 경우) 멱등함 안전함
options 주로 확인용(사용가능한지 등) 멱등함 안전함