REST는 HTTP의 메서드를 활용해 CRUD를 구현하고, URI를 통해 자원을 명시하는 등 HTTP 통신의 특성을 최대한 활용하는 아키텍처
REST API
구성 요소
자원(RESOURCE) - URI
- 자원을 구별하는 ID는 /orders/order_id/1와 같은 HTTP URI이다.
행위(Verb) - HTTP METHOD
- HTTP 프로토콜의 Method를 사용
표현(Representations)
- 리소스에 대한 표현 (HTTP Message Body)
- Client가 자원의 상태(정보)에 대한 조작을 요청하면 Server는 이에 적절한 응답
- 현재는 JSON으로 주고 받는 것이 대부분
제약 조건
Client-Server Architecture (서버-클라이언트 구조)
- REST 서버는 API 제공, 클라이언트는 사용자 인증이나 컨텍스트(세션, 로그인 정보)등을 직접 관리하는 구조로 각각 의 역할이 확실히 구분
- 클라이언트와 서버에서 개발해야 할 내용이 명확해지고 서로간 의존성이 줄어들게 된다.
Layered System (계층형 구조)
- 다중 계층으로 구성될 수 있으며 보안, 로드 밸런싱, 암호화 계층을 추가해 구조상의 유연성을 둘 수 있다.
- PROXY, 게이트웨이 같은 네트워크 기반의 중간매체를 사용할 수 있게 한다.
Stateless (무상태성)
- 세션 정보나 쿠키 정보를 별도로 저장하고 관리하지 않기 때문에 API 서버는 들어오는 요청만을 단순히 처리
Cacheable (캐시 가능)
- HTTP가 가진 캐싱 기능이 적용 가능
- Last-Modified 태그나 E-Tag를 이용하면 캐싱 구현이 가능
Self-Descriptiveness (자체 표현 구조)
- REST API 메시지만 보고도 이를 쉽게 이해 할 수 있는 자체 표현 구조
Uniform Interface
URI로 지정된 리소스에 균일하고 통일된 인터페이스를 제공
- Self-Descriptive Messages
- 각 메세지는 자신을 어떻게 처리해야 하는지 충분히 정보를 포함해야 한다.
- HATEOAS(Hypermedia As The Engine Of Application State)
- 클라이언트에 응답할 때 단순히 결과 데이터만 제공해주기 보다는 URI를 함께 제공해야 한다는 원칙이다.
- Resource Identification In Requests
- 요청에 의한 자원 식별은 웹 기반의 REST에서 자원 접근은 주로 URI를 사용한다는 것을 나타낸다.
- Resource Manipulation Through Representations
- 클라이언트가 특정 메세지나 메타 데이터를 갖고 있으면 자원을 수정, 삭제하는 충분한 정보를 갖고 있는 것
장/단점
장점
- HTTP 프로토콜의 인프라를 그대로 사용하므로 REST API 사용을 위한 별도의 인프라를 구축할 필요가 없다.
- HTTP 표준 프로토콜에 따르는 모든 플랫폼에서 사용이 가능
- REST API 메시지가 의도하는 바를 명확하게 나타내므로 의도하는 바를 쉽게 파악할 수 있다.
- 서버와 클라이언트의 역할을 명확하게 분리
단점
- HTTP Method 형태가 제한적
- REST는 HTTP 메소드를 이용하여 URI를 표현. 이러한 표현은 쉬운 사용이 가능하다는 장점이 있지만 반대로 메소드 형태가 제한적인 단점.
- 구형 브라우저가 아직 제대로 지원해주지 못하는 부분이 존재.
- (PUT, DELETE를 사용하지 못하는 점)
- 표준이 자체가 존재하지 않아 정의가 필요.
- 브라우저를 통해 테스트할 일이 많은 서비스라면 쉽게 고칠 수 있는 URL보다 Header 정보의 값을 처리해야 하므로 전문성이 요구
왜 RESTful APIs를 만드는 것일까
Client Side를 정형화된 플랫폼이 아닌 모바일, PC, 애플리케이션 등 플랫폼에 제약을 두지 않는 것을 목표로 했기 때문이다.
2010년 이전만 해도 Server Side에서 데이터를 전달해주는 Client 프로그램의 대상은 PC 브라우저로 그 대상이 명확했다.
하지만 스마트 기기들이 등장하면서 TV, 스마트 폰, 테블릿 등 Client 프로그램이 다양화되고 그에 맞춰 Server를 일일이 만든다는 것은 꽤 비효율적인 일이 되어 버렸다.
이런 과정에서 개발자들은 Client Side를 전혀 고려하지 않고 메시지 기반, XML, JSON과 같은 Client에서 바로 객체로 치환 가능한 형태의 데이터 통신을 지향하게 되면서 Server와 Client의 역할을 분리하게 되었다.
대부분 못 지키고 있는 REST 제약조건
Self-descriptive messages
- 메시지가 스스로 설명되어야 한다는 것
- 메시지의 모든 요소는 메시지만 보고 그 뜻을 알아야 한다는 것
- link header에 명세를 확인할 수 있는 링크를 넣어 응답에 넘길 수도 있을 것
Hateoas
- Hypermedia As The Engine Of Application State
- 애플리케이션 상태는 Hyperlink를 이용해서 전이가 되어야 한다.
- REST Api를 사용하는 클라이언트가 전적으로 서버와 동적인 상호작용이 가능하도록 하는 것을 의미.
이러한 방법은 클라이언트가 서버로부터 어떠한 요청을 할 때, 요청에 필요한 URI를 응답에 포함시켜 반환하는 것으로 가능하게 할 수 있다. - Client 사이드에서는 "rel"의 이름으로 요청 URI를 사용하기 때문에 URI 수정이 발생하더라도 Client 사이드는 수정이 이루어지지 않는다.
HTTP METHOD
HTTP 메서드란 클라이언트-서버 구조에서 요청(request)와 응답(response)가 이루어지는 방식을 의미.
서버가 수행해야 할 동작을 지정하여 요청(request)을 보내는 방법.
그러면 HTTP 메서드를 왜 사용할까?
결국 리소스와 동작을 구분하기 위함이다.
HTTP 메소드 종류
GET
- 리소스 조회
- 데이터를 조회하는 것이기 때문에 요청시에 Body 값과 Content-Type가 비워져있다.
- 서버에 전달하고 싶은 데이터는 query(쿼리 파라미터, 쿼리 스트링)을 통해서 전달. (클라이언트에게 전달하는 정보가 무방비로 노출되므로 주의, 브라우저 히스토리에도 기록이 남음.)
- 메시지 바디를 사용해 데이터를 전달할 수도 있지만, 지원하지 않는 곳이 많아 권장x
- 데이터 조회에 성공한다면 Body 값에 데이터 값을 저장하여 성공 응답을 보낸다.
- GET은 캐싱이 가능하여 같은 데이터를 한번 더 조회할 경우에 저장한 값을 사용하여 조회 속도가 빨라진다.
- (이미지 같은 정적 컨텐츠는 데이터 양이 크고, 변경된 일이 적기 때문에 동일한 요청이 발생했을 경우 서버로 요청을 보내지 않고 캐시된 데이터를 사용)
- 멱등성을 지님
POST
- 새로운 리소스를 생성
- 메시지 바디를 통해 서버로 요청 데이터를 전달하고 서버는 메시지 바디를 통해 들어온 데이터를 처리하여 응답
- 주로 신규 리소스를 등록하고, 프로세스 처리에 사용
- 만약 GET 메서드를 사용하는데, JSON으로 조회 데이터를 넘겨야하는 경우에는 POST를 사용
- 단순히 데이터를 생성하거나, 값을 변경하는 것을 넘어 프로세스의 상태가 변경되는 경우에 사용 ( 시스템에 큰 변화가 생길 때)
- POST로 조회가 가능하긴 하나, 해당 메서드는 멱등성을 지니지 않으므로 POST 메서드를 여러번 수행할 경우 같은 값이 나오는 것을 보장하지 않는다.
- 데이터를 전송할 때, Body에 담아 전송하므로 메시지 길이의 제한이 없다.
- 문자열 데이터 뿐만 아니라, RadioButton 같은 객체들의 값도 전송할 수 있다.
- 데이터를 생성하는 것이기 때문에 요청시에 Body 값과 Content-Type 값을 작성해야 한다.
PUT
- 리소스를 생성 / 업데이트
- 소스가 있다면 요청을 보낸 데이터로 완전히 덮어씌우고, 리소스가 없다면 새로 생성
- POST와의 차이점으로는 클라이언트가 리소스의 위치를 알고 URI를 지정 (PUT / posts/1 -> 1번 게시글 수정 요청)
- PUT은 기존 리소스를 완전히 대체하기 때문에 아래처럼 A 필드만을 변경하려고 요청을 보내면
기존 데이터를 날리고 요청한 데이터를 새로 덮어쓰기 때문에 B 필드가 제거된 채로 요청받은 A 필드만 존재하게 됨 - 멱등성을 지님
PATCH
- PUT과 다르게 PATCH는 리소스의 부분 변경
- 멱등성을 보장하도록 설계할 수 있지만, 멱등성을 보장하지 않도록 설계할 수도 있다. PATCH는 리소스의 일부에 대하여 변화를 명령할 수 있기 때문
- PUT은 새로운 자원을 생성하지만, PATCH는 새로운 자원을 생성하진 않는다.
- PATCH 메서드를 지원하지 않는 서버도 있는데, 그럴 경우 POST 사용
- 멱등성을 지니지 않음
DELETE
- 리소스를 제거
- 요청시에 Body 값과 Content-Type 값이 비워져있다.
- URL을 통해서 어떠한 데이터를 삭제할지 파라미터를 받는다.
- 데이터 삭제에 성공한다면 Body 값 없이 성공 응답만 보내게 된다.
- 멱등성을 지님
HTTP 메소드의 멱등성
동일한 요청을 한번 보내는 것과, 여러번 보내는 것이 서로 동일한 효과를 지니고, 서버의 상태도 동일하게 남을 때 해당 HTTP Method 가 멱등성을 갖는다고 이야기한다. 멱등성을 따질 때에는 서버의 상태만 바라보면 되며, HTTP 응답 Status는 신경쓰지 않아도 된다.
올바르게 구현된 REST API 의 GET, PUT, DELETE 메소드는 통계 기록(e.g. 게시물 조회수의 증가 등)을 제외하였을 경우 멱등성이 보장된다. 어떤 이유로 GET, PUT, DELETE 메소드는 멱등성이 보장되어야 할까?
- GET : 서버에 존재하는 리소스를 단순히 읽어오기만 하는 메소드이기 때문에 당연히 여러번 수행되어도 결과값은 변하지 않는다.
- PUT : 서버에 존재하는 리소스를 요청에 담긴 내용대로 통째로 대체해버리므로 올바르게 구현하였다면 여러번 수행되어도 결과 값은 변하지 않을 것이다.
- DELETE : 존재하는 데이터를 삭제한 결과와 이미 존재하지 않은 결과를 삭제하려는 시도에 대한 응답 코드는 서로 다르겠지만, (200 OK 또는 404 NOT FOUND) 서버의 상태 자체는 변하지 않으므로 올바르게 구현되었다면 여러번 수행되어도 멱등성이 보장될 것이다.
하지만, POST는 이야기가 다르다. POST 메소드가 호출될 때 마다 데이터베이스 등에 요청된 데이터가 추가될 것 이고, 이는 곧 멱등성을 위배함을 알 수 있다. 호출시 마다 서버의 상태가 달라지기 때문이다.
그렇다면 PATCH 메소드는 어떨까? 결론부터 말하자면 PATCH 메소드는 항상 멱등성을 보장한다고 이야기할 수 없다. 정확히는 PATCH는 멱등성을 보장하도록 설계할 수 있지만, 멱등성을 보장하지 않도록 설계할 수도 있다. PUT은 요청에 대하여 리소스를 통째로 바꿔버리기 때문에 멱등성이 보장되지만, PATCH는 리소스의 일부에 대하여 변화를 명령할 수 있기 때문이다.
안전한 메소드 (Safe Methods)
안전한 메소드란, 서버의 상태를 변경시키지 않는 HTTP 메소드를 의미한다. GET, OPTIONS, HEAD 와 같이 조회에 사용되는 메소드를 안전하다고 이야기할 수 있다. 모든 안전한 메소드는 멱등성을 갖지만, 그 역은 성립하지 않는다.
앞서 이야기한 PUT과 DELET 메소드는 멱등성을 갖는다고 이야기 했다. 하지만 PUT은 리소스를 수정하고, DELETE는 메소드를 제거하므로 안전한 메소드라고는 이야기할 수 없다.
즉, 멱등성을 갖는 메소드가 서버의 상태를 변경하지 않는다고 오해하면 안된다. 멱등성을 갖는 메소드도 서버의 상태를 변경시킬 수 있다. 멱등성의 핵심은 "요청에 대한 서버의 상태가 항상 같은가?" 이다.
https://developer.mozilla.org/ko/docs/Web/HTTP/Methods/PATCH
https://prinha.tistory.com/entry/HTMLWEB-HTTP-Method-GET-POST%EC%9D%98-%EC%B0%A8%EC%9D%B4
https://medium.com/@lyhlg0201/http-method-d561b77df7