본문 바로가기
Java 웹 프로그래밍

당신의 RESTful API는 정말 RESTful 한가요? - REST와 Hypertext, HATEOAS

by irerin07 2024. 1. 29.
728x90

들어가기에 앞서

이 포스팅은 REST가 뭔지 찾아보다 생각보다 더 깊은 내용이 숨어있어 여러가지로 찾아보고 정리하고자 쓴 글입니다.

해당 포스팅에 써 있는 내용이 100% 정답일 수는 없습니다. 분명 모자란 부분도 있고, 틀린 부분도 있을테고, 이상한 부분도 있을겁니다.

그래도 정말 노력하고 재미있게 쓴 포스팅이니 함께 읽어주시고 부족한 부분을 채울 수 있도록 도와주시면 감사하겠습니다.

 

 

 

REST?

REST (representational state transfer, representational 상태 전송) 란 월드 와이드 웹의 개발과 디자인을 위해 만들어진 소프트웨어 아키텍처 스타일의 한 종류이다.

 

REST는 Web과 같은 분산 하이퍼미디어 시스템의 아키텍처가 어떻게 동작해야 하는지에 대한 일련의 제약조건들을 정의합니다. 여기서 주의해야할 것은 REST는 "제약"이지 어떤 프로토콜이나 기준이 아니라는 것입니다.

 

REST는 2000년도에 로이 필딩의 박사 논문에서 소개 되었으며 그 내용은

서버는 리소스 그 자체가 아닌 리소스에 대한 representation으로 응답하고, 해당 자원은 시스템의 상태를 변경할 수 있는
하이퍼미디어 링크를 포함하고 있다.

 

는 내용입니다.

 

로이 필딩은 사람들이 아무 HTTP-based interface를 REST api라 부르는것에 실망스럽다 합니다.

지금은 찾아볼 수 없지만 필딩은 자신의 글에서 REST api라 표방하는 API를 두고 이는 REST가 아니라 RPC라고 말할 정도죠.

로이 필딩이 말하는 REST

그럼 로이 필딩이 말하는 REST란 무엇일까요? 

 

하나씩 알아봅시다.

우선 가장 윗단에 적어둔 글을 다시 가져옵시다.

REST (representational state transfer, representational 상태 전송) 란 월드 와이드 웹의 개발과 디자인을 위해 만들어진 소프트웨어 아키텍처 스타일의 한 종류이다.

REST는 Web과 같은 분산 하이퍼미디어 시스템의 아키텍처가 어떻게 동작해야 하는지에 대한 일련의 제약조건들을 정의합니다.

 

로이 필딩은 REST란 소프트웨어 아키텍처 스타일의 한 종류이고, 일련의 제약조건들을 만족하는것이 REST라고 말합니다.

그럼 그 제약조건들은 무엇이 있을까요?

 

Client-server architecture

클라이언트 - 서버 라는 제약조건은 쉽게 말하자면 관심사의 분리입니다.

유저 인터페이스와 관련된 관심사를 데이터 저장 관심사에서 분리 시키는 것으로 서버와 클라이언트의 역할을 명확히 구분해야 한다. 정도로 이해할 수 있을 것 같습니다.

이렇게 함으로써 얻을 수 있는 이점중 가장 중요한 것은 클라이언트와 서버가 독립적으로 진화하고 확장될 수 있다는 것입니다.

 

Statelessness

간단하게 말하자면, 클라이언트는 서버에 요청시 필요한 모든 정보를 전달해야 합니다.

서버는 이전 요청에 대해 어떤 정보도 유지하거나 저장하지 않기 때문에 클라이언트는 매요청시 필요한 모든 정보를 담아 서버에 요청해야 합니다.

 

 Cacheability

서버 응답은 암묵적 혹은 명시적으로 자신의 캐시 가능 여부를 정의해야 합니다.

이는 클라이언트가 응답에 포함되어있던 오래되거나 부적절한 데이터를 추가 요청에 담지 못하도록 하기 위함입니다.

 

Layered system

클라이언트는 자신이 서버에 직접 연결되어 있는지 아니면 중개서버에 연결되어 있는지 구별할 수 없습니다.

프록시나 로드 밸런서등이 서버와 클라이언트 사이에 들어와도 서버와 클라이언트간 통신을 방해하지 않고, 클라이언트나 서버 코드를 수정해야 할 일도 없어야 합니다.

 

Code on demand (optional)

서버는 자바 애플릿과 같이 컴파일된 구성 요소나 자바스크립트와 같은 클라이언트측 스크립트등을 전송하여 클라이언트의 기능을 일시적으로 확장하거나 커스터마이즈 할 수 있습니다.

 

Uniform interface

인터페이스 일관성은 제약조건은 모든 RESTful 시스템의 기본조건이라고 볼 수 있습니다. 인터페이스 일관성은 아키텍처를 단순화 하고 decouple하여 서버와 클라이언트가 독립적으로 진화할 수 있도록 합니다.

구성요소(클라이언트, 서버 등) 사이의 인터페이스는 일관성(uniform)이 있어야합니다. 

인터페이스 일관성이 지켜진다면

  • 서버 입장에선 어떤 클라이언트에게 응답을 보내도 자신이 보내주는 것을 이해할 수 있을까라는 걱정없이 표준에 의한 응답을 해줄 수 있고
  • 클라이언트 입장에선 hypertext를 통해 다음 상태로의 이동을 해야하는데, 표준화된 방식을 통해 해당 서버의 특성을 알 필요가 없어지며
  • 서로의 특성을 알지 못해도 커뮤니케이션이 가능할 수 있어져 각각 독립적으로 진화할 수 있는 유연한 시스템을 만들 수 있습니다.

인터페이스 일관성에는 네가지 제약 조건이 있습니다.

 

Resource identification in requests

각각의 자원(resource)은 요청(request)에서 식별(identification)할 수 있어야 합니다.

웹 기반 REST 시스템에서 URI를 활용해 자원을 식별하는 것을 예로 들 수 있습니다.

 

Resource manipulation through representations

클라이언트가 어떤 자원을 지칭하는 representation과 특정 메타데이터만 가지고 있다면 이것으로 서버 상의 해당 자원을 변경·삭제할 수 있는 충분한 정보를 가지고 있는 것입니다.

추가적으로 REST에서 representation이란 굉장히 중요한 내용입니다. 가능하시다면 응준님의 블로그에서 자세한 내용을 확인해보시길 추천 드립니다.

 

Self-descriptive messages

요청이나 응답 메시지에는 이를 이해하기 위한 모든 정보가 포함되어야 합니다. 예를 들자면 어떤 parser를 호출할지 media type을 통해 지정할 수 있습니다.

 

Hypermedia as the engine of application state, HATEOAS

로이 필딩이 REST에서 가장 강조하는 부분입니다. 그만큼 지켜지지 않기 때문일거라 생각합니다.

이후에 조금 더 자세히 다루겠지만 간단하게 말하자면 클라이언트는 REST 애플리케이션의 초기 URI에 접근한 이후, 서버에서 제공받은 링크를 동적으로 사용하여 자신에게 필요한 가용 자원을 찾을 수 있어야 합니다.

 

위 제약 조건 이외에도 다음과 같은 체크리스트도 만들었습니다.

 

당신의 생산물(API)을 REST API라 부르기 전에 다음 규칙들을 확인하시오:

  • REST API는 하나의 통신 프로토콜에 종속적이어서는 안된다.
  • REST API는 표준 프로토콜중 underspecified한 부분의 세부사항을 채우거나 수정하는 것 이외에는 통신 프로토콜에 대한 어떠한 변경도 포함해서는 안된다.
  • REST API는 리소스를 represent하고 응용 프로그램 상태를 구동하는 데 사용되는 media type(s)을 정의하거나 기존 표준 media types에 대한 확장 관계 이름 및/또는 하이퍼텍스트 지원 마크업을 정의하는 데 거의 모든 기술적 노력을 기울여야 한다.
  • REST API는 고정된 자원 이름이나 계층을 정의해서는 안 된다. (이는 클라이언트와 서버간의 명백한 결합을 나타낸다.)
  • REST API는 클라이언트에 중요한 리소스에 type을 지정해서는 안된다. 클라이언트에게 중요한 타입은 현재 representation의 media-type과 표준화된 relation 이름이다.
  • REST API는 초기 URI(bookmark)및 의도된 대상에게 적합한 (API를 사용할 수 있는 모든 클라이언트가 이해할 것으로 예상되는)표준 media type의 집합을 제외한 사전 지식없이 사용할 수 있어야 한다.  

원문
API designers, please note the following rules before calling your creation a REST API:

A REST API should not be dependent on any single communication protocol, though its successful mapping to a given protocol may be dependent on the availability of metadata, choice of methods, etc. In general, any protocol element that uses a URI for identification must allow any URI scheme to be used for the sake of that identification. [Failure here implies that identification is not separated from interaction.]

A REST API should not contain any changes to the communication protocols aside from filling-out or fixing the details of underspecified bits of standard protocols, such as HTTP’s PATCH method or Link header field. Workarounds for broken implementations (such as those browsers stupid enough to believe that HTML defines HTTP’s method set) should be defined separately, or at least in appendices, with an expectation that the workaround will eventually be obsolete. [Failure here implies that the resource interfaces are object-specific, not generic.]

A REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state, or in defining extended relation names and/or hypertext-enabled mark-up for existing standard media types. Any effort spent describing what methods to use on what URIs of interest should be entirely defined within the scope of the processing rules for a media type (and, in most cases, already defined by existing media types). [Failure here implies that out-of-band information is driving interaction instead of hypertext.]

A REST API must not define fixed resource names or hierarchies (an obvious coupling of client and server). Servers must have the freedom to control their own namespace. Instead, allow servers to instruct clients on how to construct appropriate URIs, such as is done in HTML forms and URI templates, by defining those instructions within media types and link relations. [Failure here implies that clients are assuming a resource structure due to out-of band information, such as a domain-specific standard, which is the data-oriented equivalent to RPC’s functional coupling].

A REST API should never have “typed” resources that are significant to the client. Specification authors may use resource types for describing server implementation behind the interface, but those types must be irrelevant and invisible to the client. The only types that are significant to a client are the current representation’s media type and standardized relation names. [ditto]

A REST API should be entered with no prior knowledge beyond the initial URI (bookmark) and set of standardized media types that are appropriate for the intended audience (i.e., expected to be understood by any client that might use the API). From that point on, all application state transitions must be driven by client selection of server-provided choices that are present in the received representations or implied by the user’s manipulation of those representations. The transitions may be determined (or limited by) the client’s knowledge of media types and resource communication mechanisms, both of which may be improved on-the-fly (e.g., code-on-demand). [Failure here implies that out-of-band information is driving interaction instead of hypertext.]

 

여기에 더해 API가 hypertext 주도로 동작하지 않는다면, RESTful하지 않고 REST API가 아니다. 라고 말합니다.

아까도 말했지만 실제로 로이 필딩은 REST API는 반드시 하이퍼텍스트 driven이어야 한다고 말할 정도로 강조하고 있는 부분입니다.

Hypertext?

위키피디아에서는 하이퍼텍스트를 다음과 같이 정의하고 있습니다.

Hypertext is text displayed on a computer display or other electronic devices with references to other text that the reader can immediately access.
Hypertext란 컴퓨터 디스플레이나 전자 제품에 표시되어 사용자가 다른 text에 즉시 접근할 수 있도록 해주는 text이다.

테드 넬슨이 1956년에 처음 선보인 이 개념은 다른 문서 혹은 동일한 문서 내에 다른 텍스트로 즉시 접근하게 해주는 text라는 뜻으로 정의 되었습니다.

 

나무위키를 생각해보시면 이해하기 조금 편하실 것 같네요. 우리가 나무위키에서 다른 문서나 혹은 같은 문서 내의 주석등으로 이동할 때 사용하는 것이라고 보시면 될 것 같습니다. 독자가 순서대로(선형적으로) 이동하는 것이 아니라 하이퍼텍스트를 사용해 원하는 대로(비선형적으로) 이동할 수 있게 해주는 것이죠.

 

그런데 로이 필딩은 어떠한 API가 RESTful 하기 위해서는 반드시 하이퍼텍스트를 가지고 있어야 한다고 합니다.

아니 그럼, 도대체 무슨 하이퍼텍스트를 가지고 있으라는 거야?

그냥 적당히 아무 하이퍼텍스트만 응답 데이터에 넣어주면 되는건가?

내 API의 모든 URI를 넣어줘야 해?

REST와 HATEOAS

REST와 하이퍼텍스트의 관계를 이해하기 위해서는 알아야할 것이 하나 더 있습니다. 

바로 HATEOAS(Hypermedia As The Engine Of Application State)입니다. 

Hypermedia As The Engine Of Application State

REST의 제약 조건들 중에 인터페이스 일관성 이라는 것이 있습니다. 

인터페이스 일관성은 RESTful한 시스템을 디자인 하기 위한 기초중의 하나입니다.

우리는 인터페이스 일관성을 통해 아키텍처를 단순화 하고 서버 클라이언트간의 결합도를 낮춰 서버와 클라이언트가 서로의 특성을 몰라도 커뮤니케이션에 지장이 없고, 독립적으로 성장할 수 있는 시스템을 만들 수 있습니다.

 

이 인터페이스 일관성을 지키기 위한 4가지 제약 조건 중 하나가 바로 Hypermedia as the engine of application state, HATEOAS 입니다.

위키피디아에서는 이를 다음과 같이 설명합니다.

Having accessed an initial URI for the REST application—analogous to a human Web user accessing the home page of a website—a REST client should then be able to use server-provided links dynamically to discover all the available resources it needs.
As access proceeds, the server responds with text that includes hyperlinks to other resources that are currently available.
There is no need for the client to be hard-coded with information regarding the structure of the server.

REST 애플리케이션의 초기 URI로 접속한 REST 클라이언트는 서버에서 제공된 링크를 동적으로 사용하여 자신에게 필요한 자원을 찾을 수 있어야 한다.
접근이 진행되면 서버는 현재 사용 가능한 다른 자원에 대한 하이퍼링크를 포함한 text로 응답한다.
클라이언트에는 서버 구조에 관한 정보가 하드코딩 되어있을 필요는 없다.

 

즉 REST 클라이언트는 서버의 특성이나 그 어떤 사전 정보 없이 하이퍼미디어를 이해할 수만 있다면 얼마든지 애플리케이션이나 서버와 통신할 수 있게 되는것이죠.

 

결국 HATETOAS의 목적은 서버-클라이언트 간 의존성을 분리해 독자적인 진화와 확장을 보조하는 것이며, hypermedia는 그 목적을 이루는 데 기여해야 한다는 것입니다.

 

REST의 하이퍼텍스트

그럼 로이 필딩이 말하는 REST에서의 하이퍼텍스트는 뭐가 다를까요?

로이 필딩은 다음과 같이 말합니다.

When I say hypertext, I mean the simultaneous presentation of information and controls such that the information becomes the affordance through which the user (or automaton) obtains choices and selects actions.

내가 말하는 하이퍼텍스트란 자원에 대한 정보와 제어(control)가 동시에 제공되어, 해당 정보들이 사용자에 선택지를 주고 동작을 결정할 수 있도록 되는것(Affordance)을 말합니다.

* Affordance란 어떤 행동을 유도한다는 뜻으로 행동유도성 이라고도 합니다.. 즉 어떤 정보를 통해 사용자의 행동을 유도하게 만드는 것이라고 이해하면 될 것 같습니다.

 

로이 필딩이 말하는 하이퍼텍스트란 기존 하이퍼텍스트에서 크게 벗어나지는 않지만, 사용자에게 어떤 자원에 대한 정보와 해당 자원을 제어할 수 있는 선택지를 주어서 사용자가 원하는대로 제어할 수 있도록 하는 것을 말합니다.

 

그러니 응답 데이터에 링크를 잔뜩 달아 전달해주면 HATEOAS가 되는건가? 아닙니다.

서버는 사용자가 요청한 자원에 대한 정보다음 액션에 대한 선택지를 클라이언트에게 줘야 하는것이 중요 포인트입니다.

 

그래서 결국 뭔데?

우리가 흔히 만들고, 사용하고, 말하는 RESTful한 API는 로이 필딩의 시선에서는 전혀 RESTful 하지 않을지도 모른다는 것입니다.

 

REST에서 중요하다 느껴지는것은 클라이언트는 서버에 대해 알 필요가 없다는 것입니다.

어떤 기능을 가지고 있는지, 어떻게 동작하는지에 대한 정보는 전혀 필요가 없습니다.

서버는 사용자가 요청한 자원에 대한 정보와 다음 액션에 대한 선택지를 클라이언트에게 주고, 클라이언트는 해당 정보와 선택지로 서버에 대한 별다른 사전 지식 없이 다음 액션을 취할 수 있다는 것이 중요한 것 같습니다.

 

누구는 말합니다.

"모든 REST의 제약 조건을 지키는 것만이 진정한 RESTful API이다!"

 

그리고 또 누구는 말합니다.

"그걸 현실적으로 어떻게 다 지키냐! 좋은것은 취하고, 맞지 않는것은 쳐내면서 발전하는것이다!"

 

Your API isn't RESTful and that's good 이라는 포스트에서는 다음과 같은 내용이 있습니다.

많은 사람들은 SOAP같이 클라이언트와 서버를 강결합 시키는 프로토콜을 대체할 간단하고 표준화된 프로토콜을 원했다.
그들의 눈에 REST의 몇가지 아이디어는 굉장히 유용하고 자신들의 원하는 바에 적합했지만, 몇가지는 별로 마음에 들지 않았다. 
그래서, 사람들은 그냥 자신들이 필요로 하는 부분만 가져다 쓰고 나머지는 신경쓰지 않기로 했다.
그러고는 REST라는 용어에 이미 굉장히 구체적인 의미와 정의가 있었음에도 불구하고 REST라는 용어를 자신들이 만든 새로운 웹 API 컨셉에 슬쩍 붙여넣었다.
로이 필딩의 노력에도 불구하고 사람들은 REST라는 용어를 납치하고 도망쳤다.
그 결과 REST, RESTful, REST API등의 용어는 모든 종류의 웹 API 구현에 부정확하게 적용되는 일이 생기고 그 결과, 로이 필딩이 정의한 REST의 실제 개념과 긴밀하게 결합된 웹 API구현 방법에 대한 Best Pratices둘 모두를 더욱 혼란스럽게 만들었다.

 

이 글을 작성하며 여러 자료들과 글을 읽기 전에는, RESTful API를 구현했냐는 질문에 항상 그렇다고 대답해 왔습니다.

 

그리고 이 글을 작성하며 여러 자료들과 글을  읽은 이후 누군가 나에게 RESTful API를 구현해봤냐 묻는다면, 아마 여전히 그렇다고 대답할 것 같습니다.

하지만 같은 질문일지라도 지금이라면, 아마 조금은 더 좋은 대답을 할 수 있을 것 같습니다.

 

그래서 여러분,

 

당신의 RESTful API는 정말 RESTful 한가요?

 

출처 : 

https://haah.kr/2017/05/22/rest-the-beginning/

https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven

https://medium.com/@trevorhreed/you-re-api-isn-t-restful-and-that-s-good-b2662079cf0e

https://www.youtube.com/watch?v=pspy1H6A3FM

https://www.youtube.com/watch?v=RY_kMXEJZfk

https://martinfowler.com/articles/richardsonMaturityModel.html

https://jinson.tistory.com/190

https://www.thoughtworks.com/insights/blog/rest-api-design-resource-modeling

https://en.wikipedia.org/wiki/REST

https://en.wikipedia.org/wiki/Hypertext

https://blog.npcode.com/2017/04/03/rest%EC%9D%98-representation%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80/

 

 

 

 

 

 

 

 

728x90