티스토리 뷰
개발 공부를 시작하고 자주 접하고 그냥 지나친 개념 중에 하나이다. 면접 질문으로도 자주 나온다고 하고, 실제로 채용공고 필요 역량에도 REST 등 인터넷 기반 프로토콜/ 기술에 대한 이해를 요구하고 있는 기업도 다수 있다.
REST(REpresentational State Transfer) '대표적인 상태 전달' 흠.. 무슨 말인지 와닿지 않는다.
REST란, "웹에 존재하는 모든 자원(이미지, 동영상, DB 자원)에 고유한 URI를 부여해 활용"하는 것으로, 자원을 정의하고 자원에 대한 주소를 지정하는 방법론을 의미한다고 한다.
따라서 Restful API는 REST 특징을 지키면서 API를 제공하는 것을 의미한다. (일종의 Coding Convention이랄까. 설계원칙, 가이드를 지키면서 개발을 하자는 의미인듯 싶다.)
그렇다면 왜 REST 개념이 대두되었을까?
큰 특징으로는 '애플리케이션 분리 및 통합', '다양한 클라이언트의 등장'이다.
애플리케이션의 복잡도가 증가하면서 애플리케이션을 어떻게 분리하고 통합하느냐가 주요 이슈가 되었고, 이에 자바 진영에서는 과거 EJB(Enterprise Java Beans), SOA(Service Oriented Architecture)에 이어 최근에는 MSA(Micro Service Architecture)와 함께 REST가 떠오르고 있는 것이다.
그리고 모바일과 같은 다양한 클라이언트의 등장하면서 Backend 하나로 다양한 Device를 대응하기 위해 REST의 필요성이 증대되었다.
그래서 REST란 무엇일까?
REST 구성- 자원 (Resouce) - URI- 행위 (Verb) - HTTP Method- 표현 (Representations)
예) /users GET /users/{id} GET /users PUT
REST의 특징1) Uniform (유니폼 인터페이스) : HTTP 표준에만 따른다면, 안드로이드/IOS 플랫폼이든, 특정 언어나 기술에 종속되지 않고 모든 플랫폼에 사용이 가능하며, URI로 지정한 리소스에 대한 조작이 가능한 아키텍처 스타일을 의미한다.
2) Stateless (무상태성) : HTTP는 Stateless Protocol 이므로, REST 역시 무상태성을 갖는다. 즉, HttpSession과 같은 컨텍스트 저장소에 상태정보를 따로 저장하고 관리하지 않고, API 서버는 들어오는 요청만을 단순 처리하면 된다. 세션과 같은 컨텍스트 정보를 신경쓸 필요가 없어 구현이 단순해진다.
3) Cacheable (캐시가능) : HTTP 기존의 웹 표준을 그대로 사용하므로, 웹에서 사용하는 기존의 인프라를 그대로 활용 가능하다. HTTP 프로토콜 기반의 로드밸런서(mod_proxy)나, SSL은 물론이고 HTTP가 가진 가장 강력한 특징 중의 하나인 캐싱 기능을 적용할 수 있다. 일반적인 서비스에서 조회 기능이 주로 사용됨을 감안하면, HTTP 리소스들을 웹 캐쉬 서버 등에 캐싱하는 것은 용량이나 성능 면에서 이점이 있다. 캐싱 구현은 HTTP 프로토콜 표준에서 사용하는 Last-Modified 태그나 E-Tag를 이용하면 가능하다.
4) Self-descriptiveness (자체 표현 구조) : 동사(Method) + 명사(URI) 로 이루어져있어 어떤 메서드에 무슨 행위를 하는지 알 수 있으며, 메시지 포맷 역시 JSON을 이용해서 직관적으로 이해가 가능한 구조로, REST API 메시지만 보고도 이를 쉽게 이해할 수 있다. 5) Client - Server 구조 : REST 서버는 API 제공, 클라이언트는 사용자 인증이나 컨텍스트(세션, 로그인 정보 등)을 직접 관리하는 구조로 각각의 역할이 확실히 구분되기 때문에 클라이언트와 서버에서 개발해야 할 내용이 명확해지고 서로간 의존성이 줄어들게 된다.
6) 계층형 구조 : API 서버는 순수 비지니스 로직을 수행하고, 그 앞단에 사용자 인증, 암호화(ssl), 로드밸런싱 등을 하는 계층을 추가하여 구조상의 유연상을 둘 수 있다. 이는 간단하게는 HA Proxy나 Apache의 Reverse Proxy를 통해, 더 나아가서는 API gateway 등을 활용하여 Micro Service Architecture로도 구현이 가능하게 한다.
REST 요소를 파악하는데는 Richardson Maturity Model(RMM)을 기준으로 이해하는 것이 좋은 것 같다.
레벨0
웹의 기본 메커니즘을 전혀 사용하지 않는 단계로, HTTP를 통해 데이터를 주고받지만 모든 데이터 요청 및 응답과 관련한 정보를 HTTP의 body 정보를 활용한다.
POST /appointmentService HTTP/1.1
[various other headers]
<openSlotRequest date = "2010-01-04" doctor = "mjones"/>
POX(Plain Old XML)로 요청과 응답을 주고받는 RPC 스타일 시스템이다. 이 때 HTTP method는 POST만 사용하며, 특정 서비스를 위해 클라이언트에서 접근할 endpoint는 하나이다.
레벨 1 - 리소스
RMM에서 REST를 위한 첫 단계는 리소스를 도입하는 것이다. 그래서 이제는 모든 요청을 단일 서비스 endpoint로 보내는 것이 아니라, 개별 리소스와 통신한다.
POST /doctors/mjones HTTP/1.1
[various other headers]
<openSlotRequest date = "2010-01-04"/>
즉, 함수를 호출하고 인자들을 넘기는 것이 아니라 다른 정보를 위해 인자들을 제공하는 특정 리소스로 요청을 보낸다. 이럴 경우의 이점은 자원이 외부에 보여지는 방식과 내부에 저장되는 방식을 분리 할 수 있다는 것이다. 예를 들면 클라이언트 단에서 완전히 다른 포맷으로 저장하더라도 JSON 형태의 데이터를 요청할 수 있다.
레벨 2 - HTTP Method
레벨 1의 URL + HTTP Method 조합으로 리소스를 구분하는 것으로 응답 상태를 HTTP Status code 를 활용한다. 현재 가장 많은 Restful API가 이 단계를 제공한다.
GET /doctors/mjones/slots?date=20100104&status=open HTTP/1.1
Host: royalhope.nhs.uk
발생한 에러의 종류를 커뮤니케이션하기 위해 상태코드(status code)를 사용하는 것, 그리고 안전한 오퍼레이션(GET 등)과 안전하지 않은 오퍼레이션 간의 강한 분리를 제공하는 것이 레벨 2의 핵심 요소이다. 우선, Status Code를 사용한다는 것은 어떤 의미일까?기존에는 유저 생성 요청을 했을 경우 302 등의 리다이렉트 요청을 서버에서 내려주는 방식이었다면,지금은 201(created)로 유저 생성 성공을 알릴 뿐 페이지 이동은 Client 단에서 해결하는 방식이다.(login의 경우 성공은 200, 실패시 인증실패는 401, 성공했으나 권한 문제시엔 403 등)즉, 서버는 순수하게 api로서의 기능만을 제공하게 된다.(view는 Client에서..)
두번째로, 강한 분리를 제공하는 것이 어떤 이점이 있는 것일까?
HTTP에서 GET은 멱등방식으로 자원을 추출하는데, 이에 어떤 순서로든, 얼마든지 호출하든 매번 같은 결과를 얻도록 한다. 이에 통신상의 모든 참여자에게 '캐싱'기능을 지원하는 다양한 방법을 제공한다.
레벨 3 - 하이퍼미디어 컨트롤
HATEOAS(Hypertext As The Engine Of Application State) 애플리케이션 상태 엔진으로서의 하이퍼미디어 ㅡㅡ..
하이퍼미디어란 하나의 컨텐츠가 텍스트나 이미지, 사운드와 같은 다양한 포멧의 컨텐츠를 링크하는 개념이다. 이것은 관련 컨텐츠를 보기위해 링크를 따라가는 방식과 유사한 방식으로 동작하는데, 클라이언트가 다른 자원에 대한 링크를 통해 서버와 (잠재적으로 상태 변이를 초래하는) 상호작용을 한다.
즉, 특정 API를 요청한 후 다음 단계로 할 수 있는 작업을 알려주는 것이며, 다음 단계의 작업을 위한 리소스의 URI를 알려주는 것이다. 이 단계를 적용하면 클라이언트에 영향을 미치지 않으면서 서버를 변경하는 것이 가능하다.
GET /doctors/mjones/slots?date=20100104&status=open HTTP/1.1
Host: royalhope.nhs.uk
HTTP/1.1 200 OK
[various headers]
<openSlotList>
<slot id = "1234" doctor = "mjones" start = "1400" end = "1450">
<link rel = "/linkrels/slot/book"
uri = "/slots/1234"/>
</slot>
<slot id = "5678" doctor = "mjones" start = "1600" end = "1650">
<link rel = "/linkrels/slot/book"
uri = "/slots/5678"/>
</slot>
</openSlotList>
단점은, 클라이언트가 수행할 작업을 찾기 위해 링크를 따라기기 때문에 컨트롤 탐색에 꽤 많은 호출이 발생할 수 있다는 것이다. 또한 복잡성이 증가할 수 있으며, HTTP 요청상에 나타나는 부하로 낮은 지연시간이 요구될 때 문제가 될 수 있다. HTTP 기반의 REST 페이로드는 JSON 또는 바이너리 등의 포맷을 지원하므로 실제로 SOAP 보다 훨씬 간결할 수 있지만 쓰리프트와 같은 바이너리 프로토콜에는 상대가 되지 못한다. 또한 웹소켓의 경우 HTTP 초기 핸드셰이크 후에 클라이언트와 서버 간에 TCP 접속이 이루어지고 브라우저에서 스트림 데이터를 보낼 때 효율적일 수 있다. 따라서 HTTP가 대규모 트래픽에는 적합할 수 있지만 TCP 또는 다른 네트워킹 기술 기반의 프토토콜과 비교하면 낮은 지연시간이 필요한 통신에는 그다지 좋은 선택이 아닐 수 있다.
이러한 단점에도 HTTP 기반의 REST는 서비스 대 서비스의 상호작용을 위해 합리적이고 기본적인 선택이다.
RMM을 통한 REST 핵심 요소
1) resouce (레벨 1의 고민) : 애플리케이션에서 제공하는 resouce를 어떻게 분할하고 통합할 것인가?
2) http method, status code (레벨 2의 고민) : 에러 상황에 대한 적절한 처리와 method 도입을 통한 불필요한 다양성(복잡성) 제거
3) hypermedia (레벨 3의 고민) : API가 스스로 문서화 가능하도록 지원할 것인가?
RESTful API 설계
1. URI는 정보의 자원을 표현해야 한다.(리소스명은 동사보다는 명사를 사용)
2. 자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE 등)으로 표현
URI 설계시 주의할 점
1. 슬래시 구분자(/)는 계층 관계를 나타내는데 사용
2. URI 마지막 문자로 슬래시(/)를 포함하지 않는다.
3. 하이픈(-)은 URI 가독성을 높이는데 사용
4. 밑줄(_)은 URI에 사용하지 않는다.
5. URI 경로에는 소문자가 적합하다.
6. 파일확장자는 URI에 포함하지 않는다.
Todo 기능을 구현한다고 가정했을 때의 Restful API 표준
endpoint | 기능 |
---|---|
GET /todos | List all todos |
POST /todos | Create a new todo |
GET /todos/:id | Get a todo |
PUT /todos/:id | Update a todo |
DELETE /todos/:id | Delete a todo and its items |
GET /todos/:id/items | Get a todo item |
PUT /todos/:id/items | Update a todo item |
DELETE /todos/:id/items | Delete a todo item |
(추가적으로) Spring Data Rest (흥미로운 부분이다. 학습 후 내용을 추가할 계획이다)
1. Richardson Maturity Model(RMM)의 레벨 3에 해당하는 hypermedia-driven HTTP resources를 제공하는 프레임워크
2. Spring Data Rest을 사용하지 않더라도 Spring Data Rest가 지원하는 HTTP method, Status Code, 기본 CRUD 자원, association resource, search resource, paging과 sorting에 따른 설계 방식을 학습하는 것도 좋은 설계 전략이다.(추가적으로) 현재 통합 테스트도구로 postman을 사용중인데, 자동화된 테스팅 도구들을 좀 더 학습할 계획이다. 그리고 Backend의 경우 api만을 제공하나, 모바일은 특성상 다양한 버젼을 관리해야 하며, 웹은 최신기능을 업데이트 하지 않아도 사용하게 되어 코드 관리하기가 쉽다.(물론 웹도 글로벌 환경, CDN 배포 시간차 등을 고려하면 2가지 정도의 버전을 관리해야 한다.) 이 경우 REST를 지키면서 하는 DB 리팩토링은 매우 어렵다. 이 부분도 학습할 계획이다. (관련 책: 리팩토링 데이터베이스)
(2017/11/24 추가)
'Programming > .common' 카테고리의 다른 글
HTML + CSS 연습 (0) | 2017.11.16 |
---|---|
Java Logging with Eclipse (0) | 2017.11.10 |
'객체 지향과 디자인 패턴' 후기 (0) | 2017.10.02 |
blocking vs non-blocking / synchronous vs asynchronous (0) | 2017.09.01 |
Travis CI 적용하기 (0) | 2017.08.24 |