Gidhub BE Developer

REST API

2018-09-17
goodGid

REST API란?

  • 기존의 Web application이 Service중심이었다면 REST는 Resource 중심이다.

  • Resource 중심으로 설계하며 CRUD에 해당하는 HTTP의 4가지 메소드( POST, GET, PUT, DELETE)를 이용한다.
    추가적으로 Patch 메소드도 존재한다.

  • REST는 리소스 지향 아키텍쳐 스타일이라는 정의 답게 모든 것을 명사로 표현을 하며, 각 세부 리소스에는 id를 붙인다.

  • 즉 사용자라는 리소스 타입을 http://myweb/users라고 정의했다면,
    terry라는 id를 갖는 리소스는 http://myweb/users/terry 라는 형태로 정의한다.


REST의 특성

[1] Uniform Interface

  • REST는 HTTP 표준에만 따른다면 어떠한 기술이라던지 사용이 가능한 인터페이스 스타일이다.
예를 들어 HTTP + JSON으로 REST API를 정의했다면
안드로이드 플랫폼 or iOS 플랫폼 or C 또는 Java/Python이건 
특정 언어나 기술에 종속 받지 않고 
HTTP와 JSON을 사용할 수 있는 모든 플랫폼에 사용이 가능한 
느슨한 결함(Loosely coupling)형태의 구조이다.
  • 흔히들 근래에 REST를 이야기 하면, HTTP + JSON을 쉽게 떠올리는데,
    JSON은 하나의 옵션일뿐, 메시지 포맷을 꼭 JSON으로 적용해야할 필요는 없다.

  • 자바스크립트가 유행하기전에만 해도 XML 형태를 많이 사용했으며
    근래에 들어서 사용의 편리성 때문에 JSON을 많이 사용하고 있지만
    XML을 사용할 경우, XPath,XSL등 다양한 XML 프레임워크를 사용할 수 있을뿐만 아니라
    메시지 구조를 명시적으로 정의할 수 있는 XML Scheme나 DTD등을 사용할 수 있기 때문에
    복잡도는 올라가더라도 메시지 정의의 명확성을 더할 수 있다.


  • 일반적인 웹 서비스의 백엔드 서버는 단순히 HTML 문서만을 응답해주기 때문에

  • 웹 브라우저 클라이언트 전용의 서버라고 생각 할 수 있다.

  • 하지만 REST API는 웹 브라우저를 포함해서 HTTP 통신이 가능한 모든 클라이언트 플랫폼을 타겟으로 한다.

  • 이런 범용성을 갖추기 위해서 REST API의 HTTP Response Body

  • HTML 보다는 JSON, XML 등 여러 플랫폼에서 사용하기 적절한 단순한 텍스트 포맷을 사용한다.


[2] 무상태성(Stateless)

  • 각 요청에 대한 컨택스트(세션,로그인 정보)가 서버에 저장되어서는 안된다.

  • REST는 Resource 중심이기 때문에 서버는 API를 통해 동작을 이해하고 Resource에 접근할 수 있다.

  • JWT Token 등을 사용하여 인증절차를 진행한다.

  • 상태가 있다 없다 의 의미는 사용자나 클라이언트의 컨택스트를 서버쪽에 유지 하지 않는다는 의미다.

  • 쉽게 표현하면 HTTP Session과 같은 컨텍스트 저장소에 상태 정보를 저장하지 않는 형태를 의미한다.

  • 상태 정보를 저장하지 않으면 각 API 서버는 들어오는 요청만을 들어오는 메시지로만 처리하면 되며,
    세션과 같은 컨텍스트 정보를 신경쓸 필요가 없기 때문에 구현이 단순해진다.


[3] 캐시 처리 가능(Cacheable)

  • www에서와 같이 클라이언트는 응답을 캐싱할 수 있어야 한다.

  • 캐싱처리가 잘되면 클리이언트-서버 간 상호작용을 부분적, 완전하게 제거하여 확장성 성능을 향상시킨다.

  • REST의 큰 특징 중의 하나는
    HTTP라는 기존의 웹 표준을 그대로 사용하기 때문에
    웹에서 사용하는 기존의 인프라를 그대로 활용이 가능하다.

  • HTTP 프로토콜 기반의 로드 밸런서나 SSL은 물론이고
    HTTP가 가진 가장 강력한 특징중의 하나인 캐슁 기능을 적용할 수 있다.

  • 일반적인 서비스 시스템에서 60 ~ 80% 가량의 트랜잭션이
    Select와 같은 조회성 트렌젝션인 것을 감안하면
    HTTP의 리소스들을 웹캐쉬 서버등에 캐슁하는 것은
    용량이나 성능 면에서 많은 장점을 가지고 올 수 있다.

  • 구현은 HTTP 프로토콜 표준에서 사용하는 Last-Modified 태그나 E-Tag를 이용하면 캐슁을 구현할 수 있다.

  • 아래와 같이 Client가 HTTP GET을 Last-Modified 값과 함께 보냈을 때,
    컨텐츠에 변화가 없다면
    REST 컴포넌트는 304 Not Modified를 리턴하며
    Client는 자체 캐쉬에 저장된 값을 사용하게 된다.

  • 이렇게 캐쉬를 사용하게 되면
    네트워크 응답시간 뿐만 아니라 REST 컴포넌트가 위치한 서버에 트랜잭션을 발생시키지 않기 때문에
    전체 응답 시간성능 그리고 서버의 자원 사용률을 비약적으로 향상 시킬 수 있다.

[4] 자기 서술성(Self-descriptiveness)

  • 별도의 문서가 필요없다.

  • API를 보고 다 알 수 있기 때문이다.

  • REST의 가장 큰 특징 중의 하나는 REST API 자체가 매우 쉬워서
    API 메시지 자체만 보고도 API를 이해할 수 있다.
    Self-descriptiveness 구조를 갖는 다는 것이다.

  • 리소스와 메서드를 이용해서 어떤 메서드에 무슨 행위를 하는지를 알 수 있으며
    또한 메시지 포맷 역시 JSON을 이용해서 직관적으로 이해가 가능한 구조이다.

  • 대부분의 REST 기반의 OPEN API들이 API 문서를 별도로 제공하고 있지만
    디자인 사상은 최소한의 문서의 도움만으로도 API 자체를 이해할 수 있어야 한다.


[5] Client-Server Structure

  • 근래에 들면서 재 정립되고 있는 특징 중의 하나는 REST가 클라이언트 서버 구조라는 것이다.

  • 서버가 클라이언트의 정보로 부터 조금은 자유로워지는 구조이다.

  • 클라이언트가 서버로 전송하는 데이터에 대한 의존성을 낮춰준다.

  • 일관적인 인터페이스로 분리되어야 한다.

  • REST 서버는 API를 제공하고, 제공된 API를 이용해서 비즈니스 로직 처리 및 저장을 책임진다.

  • 클라이언트의 경우
    사용자 인증이나 컨택스트(세션,로그인 정보)등을 직접 관리 및 책임 지는 구조로 역할이 나뉘어 지고 있다.

  • 이렇게 역할각각 확실하게 구분되면서
    개발 관점에서 클라이언트서버에서 개발해야 할 내용들이 명확하게 되고
    서로의 개발에 있어서 의존성이 줄어들게 된다.


[6] 계층형 구조 (Layered System)

  • 계층형 아키텍쳐 구조 역시 근래에 들어서 주목받기 시작하는 구조이다.

  • 클라이언트는 보통 대상 서버에 직접 연결되었는지 또는 중간 서버를 통해 연결 되었는지를 알 수 없다.

  • 중간 서버는 로드 밸런싱 기능이나 공유 캐시 기능을 제공함으로써
    시스템 규모 확장성을 향상시키는 데 유용하다.

  • 클라이언트 입장에서는 REST API 서버만 호출한다.

  • 그러나 서버는 다중 계층으로 구성될 수 있다.

  • 순수 비즈니스 로직을 수행하는 API 서버와
    그 앞단에 사용자 인증 (Authentication), 암호화 (SSL), 로드 밸런싱 등을 하는 계층을 추가해서
    구조상의 유연성을 둘 수 있다.

  • 이는 근래에 들어서 마이크로 서비스 아키텍쳐의 API Gateway나
    간단한 기능의 경우에는 HA Proxy나 Apache와 같은 Reverse Proxy를 이용해서 구현하는 경우가 많다.


  • 고전적인 프로그램 아키텍쳐는 모놀리식 아키텍쳐(Monolithic Architecture) 일체형 아키텍쳐를 따르는 경우가 많다.

  • 이는 UI와 데이터 계층, 통신 계층이 모두 일체형으로 작성된 구조를 말한다.

  • 하지만 REST 아키텍쳐는 UI 계층을 분리하여 클라이언트 프로그램의 범용성을 높힌다.

  • 또한 더 나아가서 대형 시스템의 개발에서는 하나의 응용프로그램을 계층별로 세분화하여 협업 및 배포의 효율성을 높히고

  • 확장성 있는 구조를 띄는 마이크로 서비스 아키텍쳐(Micro Service Architecture)를 지향하기도 한다.


REST 안티 패턴

GET / POST를 이용한 터널링

  • 가장 나쁜 디자인 중 하나가 GET or POST를 이용한 터널링이다.

  • http://myweb/users?method=update&id=terry이 경우가 전형적인 GET을 이용한 터널링이다.

  • 메서드의 실제 동작은 리소스를 업데이트 하는 내용인데
    HTTP PUT을 사용하지 않고 GET에 Query Parameters로 method=update라고 넘겨서
    이 메서드가 수정 메세드임을 명시했다.

  • 대단히 안좋은 디자인이며
    HTTP 메서드 사상을 따르지 않았기 때문에 REST라고 부를 수 도 없고
    또한 웹 캐쉬 인프라등도 사용이 불가능하다.

  • 또 많이 사용하는 안좋은 예는 POST를 이용한 터널링이다.

  • Insert(Create)성 Operation이 아님에도 JSON 바디에 Operation 명을 넘기는 형태이다.

  • 예를 들어 특정 사용자 정보를 가지고 오는 API를 아래와 같이 POST를 이용해서 만든 경우이다.

HTTP POST, http://myweb/users/
{  
   "getuser":{  
      "id":"terry"
   }
}

Self-descriptiveness 속성을 사용하지 않음

  • 위에서 언급한 바와 같이 REST의 특성중 하나는 자기 서술성(Self-descriptiveness) 속성이다.

  • REST URI와 메서드 그리고 쉽게 정의된 메시지 포맷에 의해서 쉽게 API를 이해할 수 있는 기능이 되어야 한다.

  • 특히나 자기 서술성을 깨먹는 가장 대표적인 사례가 앞서 언급한 GET이나 POST를 이용한 터널링을 이용한 구조가 된다.

HTTP Response code를 사용하지 않음

  • 다음으로 많이 하는 실수중의 하나가 Http Response code를 충실하게 따르지 않는 것이다.

  • 성공은 200, 실패는 500과 같이 1~2개의 HTTP response code만 사용하는 경우이다.

  • 심한 경우에는 에러도 HTTP Response code 200으로 정의한 후
    별도의 에러 메시지를 200 response code와 함께 보내는 경우이다.

  • 이는 REST 디자인 사상에도 어긋남은 물론이고 자기 서술성에도 어긋난다.


REST 문제점

JSON+HTTP 를 쓰면 REST인가?

  • REST에 대한 잘못된 이해중의 하나가, HTTP + JSON만 쓰면 REST라고 부르는 경우이다.

  • 앞의 안티 패턴에서도 언급하였듯이 REST 아키텍쳐를 제대로 사용하는 것은 리소스를 제대로 정의하고
    이에 대한 CRUD를 HTTP 메서드인 POST/PUT/GET/DELETE에 대해서 맞춰 사용하며
    에러코드에 대해서 HTTP Response code를 사용하는 등
    REST에 대한 속성을 제대로 이해하고 디자인해야 제대로된 REST 스타일이라고 볼 수 있다.

  • 수년전 뿐만 아니라 지금에도 이러한 안티 패턴이 적용된 REST API 형태가 많이 있기 때문에
    제대로된 REST 사상의 이해 후에 REST를 사용하도록 해야 한다.

표준 규약이 없다

  • REST는 표준이 없다. 그래서 관리가 어렵다.

  • SOAP 기반의 웹 서비스와 같이 메시지 구조를 정의하는 WSDL도 없고 UDDI와 같은 서비스 관리체계도 없다.

  • REST가 최근 부각되는 이유 자체가 WebService의 복잡성과 표준의 난이도 때문에 Non Enterprise 진영(Google, Yahoo, Amazone)을 중심으로 집중적으로 소개된 것이다.

  • 데이터에 대한 의미 자체가 어떤 비즈니스 요건처럼 Mission Critical한 요건이 아니기 때문에
    서로 데이터를 전송할 수 있는 정도의 상호 이해 수준의 표준만이 필요했지
    Enterprise 수준의 표준이 필요하지도 않았고 벤더들처럼 이를 주도하는 회사도 없었다.

  • 단순히 많이 사용하고 암묵적으로 암암리에 생겨난 표준 비슷한 것이 있을 뿐이다
    이런 것을 Defactor 표준이라고 부른다.

  • 그런데 문제는 정확한 표준이 없다 보니 개발에 있어 이를 관리하기가 어렵다는 것이다.

  • 표준을 따르면 몇 가지 스펙에 맞춰서 맞춰 개발 프로세스나 패턴을 만들 수 있는데
    REST에는 표준이 없으니 REST 기반으로 시스템을 설계하자면 사용할 REST에 대한 자체 표준을 정해야 하고
    어떤 경우에는 REST에 대한 잘못된 이해로 잘못된 REST 아키텍처에 ‘이건 REST다’는 딱지를 붙이기도 한다.

  • 근래에 들어서 YAML등과 같이 REST에 대한 표준을 만들고자 하는 움직임은 있으나 JSON의 자유도를 제약하는 방향이고 Learning Curve가 다소 높기 때문에 그다지 확산이 되지 않고 있다.

  • 이런 비표준에서 오는 관리의 문제점은 제대로된 REST API 표준 가이드와 API 개발 전후로 API 문서(Spec)을 제대로 만들어서 리뷰하는 프로세스를 갖추는 방법으로 해결하는 방법이 좋다.

기존의 전통적인 RDBMS에 적용 시키기에 쉽지 않다.

  • 예를 들어 리소스를 표현할 때, 리소스는 DB의 하나의 Row가 되는 경우가 많은데
    DB의 경우는 Primary Key가 복합 Key형태로 존재하는 경우가 많다.

  • DB에서는 유효한 설계일지 몰라도 HTTP URI는
    /에 따라서 계층 구조를 가지기 때문에
    이에 대한 표현이 매우 부자연스러워진다.

예를 들어 DB의 PK가 "세대주의 주민번호" + "사는 지역" + "본인 이름"일 때 
DB에서는 이렇게 표현하는 것이 이상할 것이 없으나
REST에서 이를 userinfo/{세대주 주민번호}/{사는 지역}/{본인 이름} 식으로 표현하게 되면 다소 이상한 의미가 부여될 수 있다.
  • 이외에도 Resource에 대한 Unique한 Key를 부여하는 것에 여러가지 애로점이 있는데
    이를 해결하는 대안으로는 Alternative Key(AK)를 사용하는 방법이 있다.

  • 의미를 가지지 않은 Unique Value를 Key로 잡아서 DB Table에 AK라는 필드로 잡아서 사용 하는 방법인데
    이미 Google 의 REST도 이러한 AK를 사용하는 아키텍쳐를 채택하고 있다.

  • 그러나 DB에 AK필드를 추가하는 것은 전체적인 DB설계에 대한 변경을 의미하고
    이는 REST를 위해서 전체 시스템의 아키텍쳐에 변화를 준다는 점에서
    REST 사용시 아키텍쳐적인 접근필요성을 의미한다.

  • 그래서 근래에 나온 mongoDB나 CouchDB, Riak등의 Document based NoSQL의 경우
    JSON Document를 그대로 넣을 수 있는 구조를 갖추는데
    하나의 도큐먼트를 하나의 REST 리소스로 취급하면 되기 때문에
    REST의 리소스 구조맵핑 하기가 수월하다.


REST API 보안

  • API 보안에 대해서는 백번,천번을 강조해도 과함이 없다.

  • 근래에 대부분의 서비스 시스템들은 API를 기반으로 통신을 한다.

  • App - Server 통신 or 자바스크립트 웹 클라이언트 - Server 통신등
    대부분의 통신이 API들을 이용해서 이루어지기 때문에
    한번 보안이 뚫려 버리면 개인 정보가 탈취되는 것 뿐만 아니라 많은 큰 문제를 야기할 수 있다.

인증 (Authentication)

  • 인증은 누가 서비스를 사용하는지를 확인하는 절차이다.

  • 쉽게 생각하면 웹 사이트에 사용자 아이디와 비밀 번호를 넣어서 사용자를 확인하는 과정이 인증이다.

  • API도 마찬가지로 API를 호출하는 대상(단말 or 다른 서버 or 사용자)을 확인하는 절차가 필요하고
    이를 API 인증이라고 한다.

인가 (Authorization)

  • 인가는 해당 리소스에 대해서 사용자가 그 리소스를 사용할 권한이 있는지 체크하는 권한 체크 과정이다.

  • 예를 들어 /users라는 리소스가 있을 때
    일반 사용자 권한으로는 내 사용자 정보만 볼 수 있지만
    관리자 권한으로는 다른 사용자 정보를 볼 수 있는 것과 같은 권한의 차이를 의미한다.

네트워크 레벨 암호화

  • 인증과 인가 과정이 끝나서 API를 호출하게 되면 네트워크를 통해서 데이터를 주고 받는다.

  • 이 때 해커등이 중간에 이 네트워크 통신을 낚아 채서(감청) 데이터를 볼 수 없게 할 필요가 있다.

  • 이를 네트워크 프로토콜 레벨에서 처리하는 것을 네트워크 레벨의 암호화라고 한다.

  • HTTP에서의 네트워크 레벨 암호화는 일반적으로 HTTPS 기반의 보안 프로토콜을 사용한다.

메시지 무결성 보장

  • 메시지 무결성이란 메시지가 중간에 해커와 같은 외부 요인에 의해서 변조가 되지 않게 방지하는 것을 이야기 한다.

  • 무결성을 보장하기 위해서 많이 사용하는 방식은
    메시지에 대한 Signature를 생성해서
    메시지와 같이 보낸 후에 검증하는 방식이다.

예를 들어 메시지 문자열이 있을 때
이 문자열에 대한 해쉬코드를 생성해서 문자열과 함께 보낸 후
수신쪽에서 받은 문자열과 이 받은 문자열로 생성한 해쉬 코드를 문자열과 함께 온 해쉬코드와 비교하는 방법이 있다. 

만약에 문자열이 중간에 변조되었으면
원래 문자열과 함께 전송된 해쉬코드와 맞지 않기 때문에 메시지가 중간에 변조가되었는지 확인할 수 있다.
  • 메시지의 무결성의 경우 앞에서 언급한 네트워크 레벨의 암호화를 완벽하게 사용한다면
    외부적인 요인(해커)등에 의해서 메시지를 해석 당할 염려가 없기 때문에 사용할 필요가 없다.

메시지 본문 암호화

  • 네트워크 레벨의 암호화를 사용할 수 없거나
    또는 네트워크 레벨의 암호화를 신뢰할 수 없는 상황의 경우
    추가적으로 메시지 자체를 암호화 하는 방법을 사용한다.

  • 이는 애플리케이션 레벨에서 구현하는데 전체 메시지를 암호화하는 방법과
    특정 필드만 암호화 하는 방법 두 가지로 접근할 수 있다.

  • 전체 메시지를 암호화할 경우 암호화에 소요되는 비용이 클 뿐더라
    중간에 API Gateway등을 통해서 메시지를 열어보고
    메시지 기반으로 라우팅 변환하는 작업등이 어렵기 때문에
    일반적으로 전체를 암호화 하기 보다는
    보안이 필요한 특정 필드만 암호화 하는 방법을 사용한다.


REST API 디자인 가이드

  1. URI는 정보의 자원을 표현해야 한다.(리소스명은 동사보다는 명사를 사용)
  2. 자원에 대한 행위는 HTTP Method로 표현한다.
  3. 하이픈(-)은 가독성을 높이는데 사용한다.
  4. 밑줄은 사용하지 않는다.
  5. 소문자를 사용한다.
  6. 파일확장자는 URI에 포함시키지 않는다.

Reference


Index