본문 바로가기

Dot Computer Science/Concept

[Naver DEVIEW 요약] RESTful API에 대해 잘 이해하고 있는가? REST의 출현과 올바른 사용법에 대해

    API 성숙도 수준 이해

    애플리케이션 프로그래밍 인터페이스(API) 영역에서는 분산 시스템을 구축할 때 효율성과 안정성, 확장성 때문에 REST(Representational State Transfer)라는 특정 설계 모델을 많이 사용한다. 2008년 Leonard Richardson이 도입한 RMM(Richardson Maturity Model)은 RESTful 설계 성숙도 수준을 이해하는 가이드 역할을 하며, 개발자가 API 구현의 강점과 약점을 파악할 수 있도록 해준다.

    RMM은 API 성숙도를 네 가지 수준으로 분류한다. 각 수준은 URI, HTTP 메서드 사용 및 HATEOAS(응용 프로그램 상태 엔진으로서의 하이퍼미디어 개념 준수)로 정의된다.

     

    https://blog.bytebytego.com/p/design-effective-and-secure-rest?utm_source=post-email-title&publication_id=817132&post_id=121947008&isFreemail=true&utm_medium=email

     

    레벨 0: POX Swamp

    Martin Fowler는 단순한 RPC 스타일 시스템으로 인해 이 수준을 "The Swamp of POX(Plain Old XML)"라고 불렀다. 여기서 API는 단일 URI와 단일 HTTP 메서드(일반적으로 POST)를 사용한다. 이 기본적인 RPC 스타일의 접근 방식은 시스템 리소스와 상호 작용할 수 있는 일관된 방법이 없는 HTTP 프로토콜의 풍부한 기능이 부족하다.

     

    레벨 1: 자원의 출현

    레벨 1은 RESTful 설계의 기본 개념인 리소스를 사용한다. 이 수준에서 각 리소스는 고유한 URI를 소유하여 다양한 시스템 요소의 관리 및 상호 작용을 단순화한다. 그러나 REST는 단일 HTTP 메서드인 POST에 계속 의존하므로 REST 잠재력을 모두 끌어올리기에는 한계에 부딪힌다.

     

    레벨 2: HTTP 동사

    레벨 2는 RESTful을 향한 중요한 레벨이다. 이 레벨에서 API는 작업을 수행하기 위해 리소스에 고유한 URI를 사용할 뿐만 아니라 이러한 리소스에 대한 작업에 해당하는 다양한 HTTP 메서드(예: GET, POST, PUT, DELETE)를 활용한다. 이러한 접근 방식은 API를 더욱 직관적으로 만들고 웹의 원칙에 더욱 밀접하게 맞출 수 있다. 이 레벨이 가장 많이 사용된다.

     

    레벨 3: HATEOAS

    레벨 3은 HATEOAS(Hypermedia as the Engine of Application State)을 도입한다. 이 단계의 API는 리소스 자체에 대한 정보를 제공할 뿐만 아니라 하이퍼미디어 링크를 통해 클라이언트를 관련 리소스 및 가능한 액션을 안내하여 사용성과 검색 가능성을 향상시킨다.

     

    위의 예에서 계좌 12345에 대한 조회를 요청하면 계좌 잔액($100)을 확인할 수 있을 뿐만 아니라 URI를 통해 다음 단계와 실행 방법을 안내하는 응답도 받을 수 있다. 예를 들어, /account/12345/deposit으로 이동하여 12345 계좌에 더 많은 금액을 입금할 수 있다.

     

    RMM은 API 설계에서 RESTful 원칙을 더 잘 이해하고 구현하는 데 도움이 되는 효과적인 프레임워크를 제공한다. API를 개선하기 위해 노력할 때, 레벨 2는 REST의 전제 조건이라는 점을 기억하는 것이 중요하다.

     

    [Naver DEVIEW] 그런 REST API로 괜찮은가 (REST의 출현과 올바른 사용법에 대해)

    API 이해 수준을 이해했으니 이제 REST API에 대해 더 자세히 알아보자. Naver DEVIEW에 있는 내용을 참고하여 정리하였다. 

     

    MDN에서 발췌한 REST는 다음과 같다.

    REST(Representational State Transfer)는 효율적, 안정적이며 확장가능한 분산시스템을 가져올 수 있는소프트웨어 아키텍처 디자인 제약의 모음을 나타낸다. 그리고 그 제약들을 준수했을 때 그 시스템은 RESTful하다고 일컬어진다.

     

    REST의 기본 개념은 리소스이다.

    • 리소스의 예로는 잘 정의된 상태와 관계, 표준화된 작동방식과 형식을 가지고 전송되는 문서를 들 수 있다.
    • 종종 타입이나 문서를 수정해야할 때, APIs혹은 그 서비스는 어디에선가 액션을 불러일으키지 않고 스스로 RESTful을 호출한다.

     

    Web 뒤의 기준 프로토콜인 HTTP는 문서와 하이퍼텍스트 링크 또한 전달하기 때문에, 간단한 HTTP APIs는 꼭 REST 제약을 지킬 필요가 없어도 통상적으로 RESTful APIs, RESTful services, 혹은 simply REST services라고 불린다.

    • 초보자는 REST API는 표준 웹 라이브러리 및 도구가 사용되는 HTTP서비스라고 가정해도 좋다.

     

    REST의 출현 - WEB과 API의 탄생

    REpresentational State Transfer. a way of providing interoperability between computer systems on the Internet. (wiki)

    • REST는 컴퓨터 시스템들 간에 상호 운용성을 제공하는 방법을 말한다.

     

    WEB과 API의 연혁

     

    WEB의 탄생

    '어떻게 인터넷에서 정보를 공유할 것인가?' 라는 질문에 대한 답으로 나온 것이 바로 Web(1991)이다. Web은 정보들을 다음과 같이 하이퍼텍스트로 연결했다.

    • 표현형식: HTML
    • 식별자: URI
    • 전송 방법: HTTP

     

    그래서 HTTP 프로토콜(1994 - 1996)은 더 크게 활성화되었고 여러 사람들이 설계에 나섰다. 

    • 이미 HTTP는 WEB의 전송 프로토콜로 이용되고 있었고 WEB은 급속도로 성장하고 있었다.

     

    그리고 그 중 Roy T.Fielding이라는 사람이 있었는데, 그는 HTTP를 정립하고 명세의 기능을 더하고 기존의 기능을 고쳐야하는 상황에 놓이게 되었다. 당연히 기존에 이미 구축된 WEB하고 호환성에 대해 생각할 수 밖에 없었다.

    • Roy T.Fielding: “How do I improve HTTP without breaking the Web?” 
    • "어떻게하면 WEB을 망가트리지 않고 HTTP를 확장시킬 수 있을까?' 하고 고민하다 나온 것이 HTTP Object Model이다.

     

    연구 끝에 Roy T.Fielding은 바로 4년 후에 HTTP Object Model을 REST라는 이름으로 발표하게 된다.

     

    Roy T.Fielding, Microsoft Research에서 REST를 발표했다. (1998)

     

    그리고 2년 후 다시 박사 논문으로 발표했다. (2000)

     

    API의 탄생

    그런 한편 인터넷 상에 API라는 것이 만들어지기 시작했다.

     

    Microsoft의 지원을 받아 어느 개발자들이 XML-RPC(1998) 원격으로 다른 시스템을 호출할 수 있는 프로토콜을 만든다. 이는 나중에 SOAP(Simple Object Access Protocol)이라는 이름으로 바뀐다.

     

    Salesforce라는 회사에서 거의 최초로 API를 공개한다. (2000.2) SOAP을 사용해서 API를 제작했다. 해당 API는 어떤 ID로 오브젝트 하나를 가져오는 요청 메세지인데, 이정도의 코드가 필요하다.

    • 그래서 사실 Salesforce API는 인기가 없었다. 너무 복잡했기 때문이다.
    <?xml version="1.0" encoding="utf-8"?>   
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
      xmlns:urn="urn:enterprise.soap.sforce.com">
      <soapenv:Header>
         <urn:SessionHeader>
            <urn:sessionId><b>QwWsHJyTPW.1pd0_jXlNKOSU</b></urn:sessionId>
         </urn:SessionHeader>
      </soapenv:Header>
      <soapenv:Body>
            <urn:fieldList><b>Id, Name, Website</b></urn:fieldList>
            <urn:sObjectType><b>Account</b></urn:sObjectType>
            <!--Zero or more repetitions:-->
            <urn:ids><b>001D000000HS2Su</b></urn:ids>
            <urn:ids><b>001D000000HRzKD</b></urn:ids>
         </urn:retrieve>
      </soapenv:Body>
    </soapenv:Envelope>

     

    그리고 4년 후 flickr에서도 API(2004.8)가 나왔는데 하나의 방식이 아니라 여러 옵션을 제공했는데, 그 옵션들은 바로 SOAPREST였다.

     

    SOAP

    <?xml version="1.0" encoding="utf-8" ?>
    <s:Envelope xmlns:s="http://www.w3.org/2001/06/soap-envelope">
    	<s:Body>
    		<s:Fault>
    			<faultcode>flickr.error.[error-code]</faultcode>
    			<faultstring>[error-message]</faultstring>
    			<faultactor>http://www.flickr.com/services/soap/</faultactor>
    			<details>Please see http://www.flickr.com/services/docs/ for more details</details>
    		</s:Fault>
    	</s:Body>
    </s:Envelope>

     

    REST

    <?xml version="1.0" encoding="utf-8" ?>
    <rsp stat="fail">
    	<err code="[error-code]" msg="[error-message]" />
    </rsp>

     

    해당 코드를 직관적으로 보기만해도 REST가 엄청 간단하다는 것을 알 수 있다.

     

    SOAP REST
    복잡하다 단순하다
    규칙이 많다 규칙이 적다
    어렵다 쉽다

     

    그 결과 REST는 많은 관심을 받게되고 결국 SOAP도 제치게 되었다.

    • 2006년, AWS가 자사 API의 사용량의 85%가 REST임을 밝혔다
    • 2010년, Salesforce.com도 REST API를 추가하기로 발표하면서 REST의 승리를 알렸다.

     

    SOAP API vs REST API

     

    그러면 우리가 사용하는 것은 REST인가?

    그렇게 WEB API가 REST로 정착이 되는 줄 알았지만 2008년에 CMIS가 나왔다.

     

    CMIS (2008)

    • CMS를 위한 표준
    • EMC, IBM, Microsoft등이 함께 작업
    • REST 바인딩 지원

     

    그리고 2016년에 Microsoft가 REST API 가이드라인을 내세웠다.

    Microsoft REST API Guidelines (2016)

     

    그런데 Roy T.Fielding이 이들을 보고 다음과 같은 말을 했다.

    • CMIS (2008)을 보고 “No REST in CMIS”라고 CMIS는 REST를 사용하지 않고 있다고 말했다.
    • Microsoft REST API Guidelines (2016)을 보고 “s/REST API/HTTP API/”라고 하면서 해당 가이드라인은 REST API가 아니고 그냥 HTTP API라고 해야한다고 말했다.
    • “REST APIs must be hypertext-driven”
    • “REST API를 위한 최고의 버저닝 전략은 버저닝을 안하는 것”

     

    사람들이 알고있는 REST API와 정작 REST를 만든 Roy T.Fielding이 말하는 REST의 갭은 너무나도 컸다. 대체 뭐가 문제였을까?

     

    REST API

    말 그대로 REST 아키텍쳐 스타일을 따르는 API이다.

     

    REST

    분산 하이퍼미디어 시스템(예: 웹)을 위한 아키텍쳐 스타일 - Roy T.Fielding 논문

    • 아키텍쳐 스타일은 제약조건의 집합이다.
    • 즉, 제약 조건을 모두 지켜야 REST를 따른다고 말하는 것이 가능하다.

     

    REST를 구성하는 스타일

    REST를 구성하는 스타일은 총 6가지로, client-server, stateless, cache, uniform interface, layered system, code-on-demand (optional)이 있다.

    client-server

    • 서버는 API를 제공하며, 클라이언트는 사용자 인증, Context(세션, 로그인 정보) 등을 직접 관리하는 구조로 각각의 역할을 확실히 구분시킴으로써 서로간의 의존성이 줄어들게 된다.
    • RestAPI에서 자원을 가지고 있는 쪽이 서버, 자원을 요청하는 쪽이 클라이언트에 해당한다.

     

    stateless

    • 각각의 요청을 별개의 것으로 인식하고 처리해야 하며,이전 요청이 다음 요청에 연관되어서는 안 된다.
    • 그래서 RestAPI는 세션정보나 쿠키 정보를 활용하여 작업을 위한 상태 정보를 저장 및 관리하지 않는다. 
    • 이러한 무상태성으로 인해 REST API는 서비스의 자유도가 높으며, 서버의 처리방식에 일관성을 부여하고 불필요한 정보를 관리하지 않기 떄문에 부담을 줄여준다. 그리고 무엇보다 구현이 단순하다.

     

    cache

    • RestAPI는 HTTP라는 기존의 웹 표준을 그대로 사용하기 때문에, 웹의 기존 인프라를 그대로 활용할 수 있다. 
    • 그러므로 RestAPI에서도 캐싱 기능을 적용할 수 있는데, HTTP 프로토콜 표준에서 사용하는 Last-Modified Tag 또는 E-Tag를 이용하여 캐싱을 구현할 수 있고, 이것은 대량의 요청을 효율적으로 처리할 수 있게 도와준다.

     

    uniform interface

    • Resource(URI)에 대한 요청을 통일되고, 한정적으로 수행하는 아키텍처 스타일을 의미한다. 
    • 이것은 요청을 하는 Client가 플랫폼(Android, IOS, JSP 등) 에 무관하며, 특정 언어나 기술에 종속받지 않는 특징을 의미하고, 이러한 특징 덕분에 REST API는 HTTP를 사용하는 모든 플랫폼에서 요청 가능하며,느슨한 결합) 형태를 갖게 되었다.

     

    layered system

    • RestAPI의 서버는 다중 계층으로 구성될 수 있으며 보안, 로드 밸런싱, 암호화 등을 위한 계층을 추가하여 구조를 변경할 수 있다.
    • 또한 Proxy, Gateway와 같은 네트워크 기반의 중간 매체를 사용할 수 있게 해준다

     

    code-on-demand (optional)

    • 서버에서 코드를 client로 보내서 실행할 수 있어야 한다.(ex. javascript)

     

    대체 HTTP만 잘 따라와도 client-server, stateless, cache, layered system은 지키기 쉽다. REST가 아니라고 하는 것은 이 중 uniform interface를 만족하지 못하는 경우가 대부분이었다.

     

    uniform interface의 제약조건

    identification of resources

    • uri가 리소스로 식별되면 된다.

     

    manipulation of resources through representations

    • 리소스에 대한 조작 시 http 메세지에 표현을 담아서 전송해서 달성하면 된다.

     

    self-descriptive messages

    • 메세지는 스스로 설명해야 한다.

     

    hypermedia as the engine of application state (HATEOS)

    • 애플리케이션의 상태는 Hyperlink를 이용해 전의되어야 한다.

     

    identification of resources, manipulation of resources through representations은 대부분 잘 지켜지고 있지만, 오늘날 자칭 REST API로 알려져있는것 들은 3,4번째 조건(self-descriptive messages, hypermedia as the engine of application state (HATEOS)) 을 지키지 못하고 있다.

     

    self-descriptive messages

    REST하려면 메세지가 스스로 자신을 설명할 수 있어야 한다.

     

    예를 들어보자 다음 메세지는 과연 self-descriptive한가?

    • 그렇지 않다. 어디로 향하는지 알 수가 없기 때문이다.

     

    self-descriptive하지 않다.

     

    그래서 목적지를 추가해줘야 한다.

    • Host: www.example.org

     

    목적지를 추가한다

     

    예2) 아래의 메세지는 이해할 수 없다. 포맷도 모르겠고, op나 path가 무엇을 뜻하는지도 알 수 없다.

    • 전혀 self-descriptive하지 않다.

    self-descriptive하지 않다.

     

    그래서 뭐로 되어있는지 일단 Content-type을 추가해줘야 한다.

    • Content-type: application-json → 아하 json 포맷으로 되어있구나
    • 그런데 아직도 op? path?를 이해하지 못한다.

     

    Content-type 추가

     

    그래서 -patch+json을 추가해줘야 한다.

    • 이제 self-descriptive하다.

    이제 self-descriptive하다.

     

     

    self-descriptive messages는 해당 메세지를 봤을 때 내용이 온전히 메세지 내용만으로도 이해가 가야한다. 오늘날 API는 해당 부분을 상당히 만족하지 못하고 있다. Media-type만 봐도 대부분 json으로만 되어있는 것을 볼 수 있다.

     

    hypermedia as the engine of application state (HATEOS)

    애플리케이션의 상태는 Hyperlink를 이용해 전이되어야한다.

    • 루트 → 글 목록 보기 GET → 글 쓰기 GET → 글 저장 POST → 생성된 글 보기 GET → 목록 얻기 GET → ...

     

    애플리케이션 상태 전이

     

    HTML을 보면 HATEOS를 만족한다.

    • a 태그를 통해 hyperlink가 나와있고 해당 hyperlink를 통해서 그 다음 상태로 전이가 가능하기 때문에 HATEOS를 만족한다.

     

    HTML

     

    JSON으로 표현한다고 해도 HATEOS를 만족할 수 있는 방법이 있다.

    • Link라는 헤더를 통해 hyperlink로 연결되어있는 리소스를 가르킬 수 있다.

     

    JSON

     

    왜 uniform interface가 필요한가?

    바로 서버와 클라이언트가 독립적 진화를 하기 위해서이다.

    • 서버와 클라이언트가 각각 독립적으로 진화한다.
    • 서버의 기능이 변경되어도 클라이언트를 업데이트할 필요가 없다.
    • REST를 만들게 된 계기: “How do I improve HTTP without breaking the Web.”

     

    독립적으로 진화한다면 어떻게 될까?

    • 서버의 기능이 바뀌었다. 새로운 API가 추가되면서 기존 API 변경/ 삭제되고 URI가 바뀔 수도 있다.
    • 하지만 클라이언트는 바뀌지 않아도 된다.

     

    이러한 독립적인 진화를 달성하기 위해서는 uniform interface 제약 조건이 필수다.

    • 애초에 REST를 만들게 된 계기 또한 "어떻게하면 WEB을 망가트리지 않고 HTTP를 확장시킬 수 있을까?'을 기억하면 당연한 일이다.

     

    WEB은 REST하다.

    실제로 REST가 지켜지고 있는가? WEB을 살펴보자.

    • 웹 페이지를 변경했다고 웹 브라우저를 업데이트할 필요는 없다.
    • 웹 브라우저를 업데이트했다고 웹 페이즈를 변경할 필요도 없다.
    • HTTP 명세가 변경되어도 웹은 잘 동작한다.
    • HTML 명세가 변경되어도 웹은 잘 동작한다.

     

    모바일은 REST하지 않다.

    모바일에서 이와 같은 것이 지켜지고 있을까? 그렇지는 않다.

    • REST로 통신하고 있지 않기 때문에 서버에서 업데이트가 발생하면 지속적으로 호환성을 맞추기위해 클라이언트도 업데이트를 해줘야한다.

     

    WEB은 어떻게 REST를 가능하게 했을까?

    마법은 없다. 그냥 다음과 같은 분들이 피땀흘려 노력을 했을 뿐이다.

    • W3C Working groups
    • IETF Working groups
    • 웹 브라우저 개발자들
    • 웹 서버 개발자들
    • 이들은 HTML5 첫 초안에서 권고안 나오는데까지 6년, HTTP/1.1 명세 개정판 작업하는데 7년이 걸렸다.

     

    상호운용성(interoperability)에 대한 집착

    • Referer 오타지만 안 고침
    • charset 잘못 지은 이름이지만 안 고침 → 원래는 encoding으로 짓는게 맞음
    • HTTP 상태 코드 418 포기함 (I’m a teapot) → HTCPCP에서 사용되는 코드
    • HTTP/0.9 아직도 지원함 (크롬, 파이어폭스)

     

    25년전 Referer 오타를 냈지만 고치지 않았다. 이름도 잘못지었지만 고치지 않았다. HTTP 상태 코드 418이 HTTP도 아닌 HTCPCP의 코드와 중복이 된다고 포기했다. HTTP 버전이 올라가면서 예전 버전을 버리려했지만 몇몇 프록시 오작동으로 인해 아직도 HTTP/0.9를 지원한다. 이 모든게 다 상호운용성에 대한 집념이 있기 때문에 가능했다.

     

    REST가 웹의 독립적 진화에 도움을 주었나

    • HTTP에 지속적으로 영항을 줌
    • Host 헤더 추가
    • 길이 제한을 다루는 방법이 명시 (414 URI Too Long 등)
    • URI에서 리소스의 정의가 추상적으로 변경됨: “식별하고자 하는 무언가”
    • 기타 HTTP와 URI에 많은 영향을 줌
    • HTTP/1.1 명세 최신판에서 REST에 대한 언급이 들어감
    • Reminder: Roy T.Fielding이 HTTP와 URI 명세의 저자 중 한명이다.

     

    그럼 REST가 성공했는가

    • REST는 웹의 독립적 진화를 위해 만들어졌다
    • 웹은 독립적으로 진화하고 있다.
    • 성공!

     

    그런데 REST API는?

    • REST API는 REST 아키텍쳐 스타일을 따라야한다.
    • 오늘날 스스로 REST API라고 하는 API들의 대부분이 REST 아키텍쳐 스타일을 따르지 않는다.

    아니 REST API가 굳이 저 제약조건들을 다 지켜야 하는건가? 그렇다고 한다.

    An API that provides network-based access to resources via a uniform interface of self-descriptive messages containing hypertext to indicate potential state transitions might be part of an overall system that is a RESTful application - Roy T. Fielding

    하이퍼텍스트를 포함한 self-descriptive한 메시지의 uniform interface를 통해 리소스에 접근하는 API

     

    그래서 REST를 초기 도입했을 때는 SOAP보다 쉽다고 생각했는데 결국엔 아니었다. 둘다 어려웠다.

     

    SOAP REST
    복잡하다 단순하다
    규칙이 많다 규칙이 적다
    어렵다 쉽다 어렵다!

     

    그러면 원격 API가 꼭 REST API여야 하는건가? 그렇지 않다.

    • “시스템 전체를 통제할 수 있다고 생각하거나, 진화에 관심이 없다면, REST에 대해 따지느라 시간을 낭비하지마라” 라고 Roy T.Fielding이 말했다. 
    • 그런데 변화가 당연시되는 전체적인 개발 시스템 구조에서 전체를 통제할 수 있다고 생각하는 것은 기만이고, 시스템 진화(확장)에 관심이 없다는 것 또한 호환성을 전혀 고려하지 않고 개발한다는 것인데 이게 말이되나...?
    • 결국에는 사이드 프로젝트같은 작은 규모 시스템이 아니라면 무조건 REST API를 따라야 한다는 소리로 들린다.

     

    우리에게 3가지 옵션이 있다.

    1. REST API를 구현하고 REST API라고 부른다.
    2. REST API 구현을 포기하고 HTTP API라고 부른다.
    3. REST API가 아니지만 REST API라고 부른다. (현재 상태)

     

    어떻게 하든 상관없는데 제약조건을 따르지 않는다면 REST API라고 부르지는 말아달라 - Roy T.Fielding 

     

    RESTful한 API 만들어보기

    사실상 어느정도 확장성을 두고 규모있는 시스템을 원하는 프로젝트라면 옵션은 하나다. REST API를 구현하고 REST API라고 불러야 한다.

     

    일단 왜 API는 REST가 잘 안되나

    일반적인 웹과 비교를 해보자. 흔한 웹페이지와 HTTP API를 비교해보면 문제는 API의 Media Type에 있음을 유추해 볼 수 있다.

     

      흔한 웹 페이지 HTTP API
    Protocol HTTP HTTP
    커뮤니케이션 사람 - 기계 기계 - 기계
    Media Type HTML JSON

     

    그러면 JSON과 HTML의 차이는 뭘까? Self-descriptive 측면에서 보면 JSON은 불완전하다. 불완전 하다는 것은 문법은 정의되어 있다는 소리이다.

    • 어떻게 파싱하고 array를 어떻게 해석하라 까지는 되어있지만, key-value에 대한 의미는 정의되어 있지 않은 것이다.
    • JSON은 문법 해석은 가능하지만, 의미를 해석하려면 별도로 문서가 (API 문서 등) 필요하다.

     

      HTML JSON
    Hyperlink 됨 (a 태그 등) 정의되어있지 않음
    Self-descriptive 됨 (HTML 명세) 불완전*

     

    간단하 Todo 리스트로 비교해보자

    • HTML은 Self-descriptive한가? HATEOAS를 만족하는가?
    • JSON은 Self-descriptive한가? HATEOAS를 만족하는가?

     

    HTML vs JSON

     

    HTML

    Self-descriptive

    1. 응답 메시지의 Content-Type을 보고 미디어 타입이 text/html임을 확인한다.
    2. HTTP 명세에 media type은 IANA에 등록되어 있다고 하므로,  IANA에서 text/html의 설명을 찾는다.
    3. IANA에 따르면 text/html 명세는 http://www.w3.org/TR/html 이므로 링크를 찾아가 명세를 해석한다.
    4. 명세에 모든 태그의 해석 방법이 있으므로 이를 해석하여 문서 저자가 사용자에게 해주려고 했던 모든 일들을 해줄 수 있다.
    5. SUCCESS

    HATEOAS

    1. a 태그를 이용해 표현된 링크를 통해 다음 상태로 전이될 수 있으므로 HATEOS를 만족한다.
    2. SUCCESS

     

    JSON

    Self-descriptive

    1. 응답 메시지의 Content-Type을 보고 media type이 application/json임을 확인한다.
    2. HTTP 명세에 media type은 IANA에 등록되어 있다고 하므로, IANA에서 application/json의 설명을 찾는다.
    3. IANA에 따르면 application/json 명세는 draft-ietf-jsonvis-rfc7159bis-04 이므로 링크를 찾아가 명세를 해석한다.
    4. 명세에 JSON 문서 파싱 방법이 명시되어있으므로 성공적으로 파싱에 성공한다. 그러나 "id"가 무엇을 의미하고, "title"이 무엇을 의미하는지 알 방법이 없다.
    5. FAIL

     

    HATEOAS

    1. 다음 상태로 전이할 링크가 없다.
    2. FAIL

     

    그런데 Self-descriptive와 HATEOAS가 독립적 진화에 어떻게 도움이 될까?

    아까 uniform interface는 독립적 진화를 위해 지켜야 하는 제약조건임은 이해했다. 그런데 그 안에 있는 이 2개의 문제점들은 독립적 진화와 어떤 연관성이 있는 것일까?

     

    Self-descriptive은 확장 가능한 커뮤니케이션을 가능하게 한다.

    서버나 클라이언트가 변경되더라도 오고가는 메시지는 언제나 Self-descriptive 하므로 언제나 해석이 가능하다.

     

    HATEOAS는 애플리케이션 상태 전이의 late binding이 가능하게 한다.

    어디서 어디로 전이가 가능한지 미리 결정되지 않는다. 어떤 상태로 전이가 완료되고 나서야 그다음 전이될 수 있는 상태가 결정된다.

    • 쉽게 말해서: 링크는 동적으로 변경될 수 있다.

     

    JSON을 REST API하게 고치기

    Self-descriptive

    방법 1: Media type 정의 (link)

    1. 미디어 타입을 하나 정의한다.
    2. 미디어 타입 문서 작서를 작성한다. 이 문서에  "id", "title"가 뭔지 의미를 정의하는 것이다.
    3. IANA에 미디어 타입을 등록한다. 이 때 만든 문서를 미디어 타입의 명세로 등록한다.
    4. 이제 이 메세지를 보는 사람은 명세를 찾아갈 수 있으므로 메세시지 의미 온전히 해석할 수 있다.
    5. SUCCESS

     

    방법 1: Media type 정의

    단점: Media type을 새로 정의하는 방법이 있지만 매번 무척 번거롭다.

     

    방법 2: Profile (link)

    1. "id", "title"가 뭔지 의미를 정의한 명세를 작성한다.
    2. Link 헤더에 profile relation으로 해당 명세를 링크한다.
    3. 이제 메세지를 보는 사람은 명세를 찾아갈 수 있으므로 이 문서의 의미를 온전히 해석할 수 있다.
    4. SUCCESS

     

    방법 2: Profile

     

    단점: 클라이언트의 역할이 늘어나고 Content negotiation이 안된다.

     

    HATEOAS

    방법 1: data에 다양한 방법으로 하이퍼링크를 표현한다.

    1. 본문에다 링크를 직접 명시하는 방법이 있지만 링크를 표현하는 방법을 직접 정의해야 한다.

     

    본문에다 링크를 직접 명시하는 방법

     

    2. 링크를 따로 빼서 정의하는 방법도 있지만 이도 매번 표현하는 방법을 직접 정의해줘야 한다.

     

    링크를 따로 빼서 정의하는 방법

     

     

    3. 하이퍼 링크를 표현하는 방법을 정의한 명세를 활용하는 방법이 있지만 기존 API를 많이 고쳐야 한다. (침투적)

    • JSON으로 하이퍼링크를 표현하는 방법을 정의한 명세들을 활용한다.
      • JSON API
      • HAL
      • ....

     

    하이퍼 링크를 표현하는 방법을 정의한 명세를 활용하는 방법

     

    방법 2: HTTP 헤더로

    1. HTTP 헤더로 표현하는 방법(Link, Location 등)이 있지만 표현에 한계가 있다.

     

    HTTP 헤더로 표현하는 방법

     

    → HATEOAS는 data, 헤더 모두 활용하면 좋다.

     

    Hyperlink는 반드시 uri여야 하는건 아닌가?

    그렇지 않다. 단지 hyperlink라는 것만 표현되기만 하면 상관없다.

     

    Media type 등록은 필수인가?

    • 아니다. 의도한 저자가 이해할 수만 있으면 상관없다.
    • 만약 사내 API이고 Media type을 이해하고 있다면 굳이 IANA에 등록하지 않아도 된다.
    • 하지만 하면 좋다.

     

    Media type을 IANA에 등록하기

    • 누구나 쉽게 사용할 수 있게 된다.
    • 이름 충돌을 피할 수 있다.
    • 등록이 별로 어렵지 않다(고 주장함)

     

    정리

    • 오늘날 대부분의 “REST API”는 사실 REST를 따르지 않고 있다.
    • 왜냐하면 REST 제약조건 중에서 특히 Self-descriptiveHATEOAS를 잘 만족하지 못한다.
    • REST는 긴 시간에 걸쳐(수십년) 진화하는 웹 애플리케이션을 위한 것이다.
    • REST를 따를 것인지는 API를 설계하는 이들이 스스로 판단하여 결정해야한다.
    • REST를 따르겠다면, Self-descriptive와 HATEOAS를 만족시켜야한다.
      • Self-descriptive는 custom media type이나 profile link relation 등으로 만족시킬 수 있다.
      • HATEOAS는 HTTP 헤더나 본문에 링크를 담아 만족시킬 수 있다.
    • REST를 따르지 않겠다면, “REST를 만족하지 않는 REST API”를 뭐라고 부를지 결정해야 할 것이다.
      • HTTP API라고 부를 수도 있고
      • 그냥 이대로 REST API라고 부를 수도 있다. (근데 roy가 싫어한다...)

    Self-descriptive와 HATEOAS가 독립적 진화에 어떻게 도움이 될까?

    독립적인 진화를 달성하기 위해서는 uniform interface 제약 조건이 필수다.

    • 애초에 REST를 만들게 된 계기 또한 "어떻게하면 WEB을 망가트리지 않고 HTTP를 확장시킬 수 있을까?'을 기억하면 당연한 일이다.
    • uniform interface에 4가지 제약 조건이 있는데 그 중 가장 안지켜지는 2가지 제약 조건은 Self-descriptive, HATEOAS이다. 
    • Self-descriptive은 확장 가능한 커뮤니케이션을 가능하게 한다.
      • 서버나 클라이언트가 변경되더라도 오고가는 메시지는 언제나 Self-descriptive 하므로 언제나 해석이 가능하다.
    • HATEOAS는 애플리케이션 상태 전이의 late binding이 가능하게 한다.
      • 어디서 어디로 전이가 가능한지 미리 결정되지 않는다. 어떤 상태로 전이가 완료되고 나서야 그다음 전이될 수 있는 상태가 결정된다.
      • 쉽게 말해서: 링크는 동적으로 변경될 수 있다.

     


    출처

    그런 REST API로 괜찮은가 - 이응준 개발자님

     

    (본인) 솔직히 내용을 정독하며 블로그에 글을 정리하면서도 계속해서 생각 든 것이 REST API가 이토록 설계하기 어려운 것이었나. 굳이 이렇게 까지 지키면서 API 설계를 해야되나 싶었다. 그런데 아직 깊이가 얕아 약간의 의구심만 들뿐 어떤 강한 확신이나 의심은 할 수 가 없었다. 독립적인 진화... 일관성... 확장성과 안전성... self-descriptive와 HATEOS... 그래서 다들 어떻게 생각하고 있나 더 찾아봤다.


    추가하여 찾은 REST에 관련한 좋은 블로그 글들

    REST 시리즈 (1~7)

    1. 긴 여정의 시작
    2. HTML Form에서 GET/ POST만 지원하는 이유
    3. REST 논문 훑어보기
    4. REST 좋아하시네
    5. Roy가 입을 열다
    6. 당신이 만든 건 REST가 아니지만 괜찮아

    REST에 대한 개발자 커뮤니티 상황을 친절히 번역까지 해주시면서 잘 정리해주셨다. RESTful API 설계를 이들만큼 안만들어봐서 그런지 아직 그들의 고민들이 와닿지는 않는다. 계속해서 볼 블로그 내용이다.

    REST를 CRUD로 치환하는 순간 이견은 좁혀지지 않는다.

    조회/등록/수정/삭제를 GET/POST/PUT/DELETE로 처리하는 게 REST라고 생각하면 더 이상의 이성적인 논쟁은 불가능해진다


    ‘REST API는 GET/POST/PUT/DELETE를 쓰는 것이다’라는 공식은 웹 프레임웍의 잘못된 가이드에도 원인이 있기도 하다.


    (본인) 블로그 글 중에 해당 내용이 있는데 뜨끔했다... 솔직히 나는 그냥 CRUD로 대입해서 생각했다. 그래서 깊게 공부할 생각조차 하지 못했다. 이번에 REST에 대해 그나마 조금은 알게 되어서 다행이다. 이번 공부를 통해 API 설계에 대한 시야가 넓어진 기분이다!

     


     

    [REST] The Resource-Oriented Architecture-1

    [REST] The Resource-Oriented Architecture-2

    2008년도 글인데, 시기상 SOAP에서 REST로 거의 넘어 온 시기에 쓴 블로그 글이다. 기본적인 개념을 정말 이해하기 쉬운 예제와 같이 잘 설명해주시고 Uniform Interface의 중요성에 대해 잘 풀어주셨다. RESTful API를 설계하면서 계속해서 들여다봐야겠다.

    Resource-Oriented Architecture
    ROA는 REST 기반(이하 RESTful) 웹서비스를 만들기 위한 문제점을 해결하는 방법을 제공한다.

    ROA는 RESTful 아키텍처이다.

    Resource란 참조하거나 그 자체로 충분히 중요한 무엇이다. (음.. 그냥 사용할 수 있는 모든 자원으로 이해해도 무리가 없다.) 보통 resource는 문서, 데이터베이스의 row또는 알고리즘 실행결과 등과 같이 컴퓨터에 저장되고 비트의 스트림으로 표현된다.

    ...

    왜 안전성과 멱등이 중요할까?
    안전성과 멱등은 신뢰할 수 없는 네트워크 상의 HTTP를 신뢰할 수 있게 만들어 준다. 만일 GET 요청을 보내고 응답을 못 받았을 경우 그냥 한 번 더 보내면 된다. 이 동작은 안전하다. 먼저 보낸 요청이 벌써 처리되었다 하더라도 서버에 다른 영향은 없다. 마찬가지로 PUT 요청을 보내고 응답을 못 받았다면 단지 한 번 더 동일한 요청을 보내면 된다.

    그러나 POST는 안전하지도 않고 멱등도 아니다. 따라서 POST 메소드는 주의해서 사용해야 한다.

    ...

    왜 Uniform Interface가 중요한가?
    중요한 것은 일관성(Uniformity)이다. 모든 서비스는 동일한 방법으로 HTTP 인터페이스를 사용한다.

    Uniform Interface가 없다면 매번 각 서비스가 어떻게 정보를 주고 받는지 배워야 한다. 하나의 서비스에서도 서로 다른 리소스에 대해 규칙이 서로 다를 것이다.

     

    Web API Design - Crafting Interfaces that Developers Love (Brian Mulloy)

    https://pages.apigee.com/rs/apigee/images/api-design-ebook-2012-03.pdf


    REST API를 잘 만드는 방법 스크랩

    How to design better APIs - Ronald Blüth

    https://r.bluethl.net/how-to-design-better-apis

     

    MicroSoft REST API 가이드라인

     

    stackOverflow REST API 가이드라인