REST에 대해 잘 아나요? 그럼 HATEOAS 는요?

RexiaN·2025년 6월 3일
1

TL;DR: Roy Fielding이 정의한 진정한 REST의 핵심은 HATEOAS(하이퍼미디어를 애플리케이션 상태의 엔진으로 사용)로, 단순히 JSON 데이터만 주고받는 것을 넘어 응답에 다음 가능한 액션을 위한 링크를 포함하는 것이다.

REST에 대해 잘 아는가? 그럼 HATEOAS는?

현대의 웹 개발에서 REST(Representational State Transfer)는 API 설계의 표준처럼 자리 잡았다. "내 API는 RESTful하다!"라고 말하는 개발자를 쉽게 만난다. 하지만 REST의 진정한 의미와 핵심 원칙에 대해 깊이 파고들면, 내가 흔히 사용하는 RESTful API가 사실은 Roy Fielding이 정의한 REST의 이상적인 모습과는 거리가 있다는 것을 알게 된다. 특히 HATEOAS(Hypermedia as the Engine of Application State)라는 개념은 REST의 심장부와도 같다.


잠깐, REST는 무엇인가?

REST는 웹과 같은 분산 하이퍼미디어 시스템을 위한 아키텍처 스타일이다. 복잡한 시스템을 효율적으로 관리하고 확장하기 위한 일련의 제약 조건(Constraints)을 제시한다. 주요 제약 조건은 다음과 같다:

  • 클라이언트-서버: 관심사의 분리 (클라이언트와 서버가 서로 독립적)
  • 무상태(Stateless): 서버는 클라이언트의 상태를 저장하지 않음
  • 캐시 가능(Cacheable): 응답을 캐시하여 성능 향상
  • 통합 인터페이스(Uniform Interface): 일관된 방식으로 자원에 접근하고 조작
  • 계층화된 시스템(Layered System): 중간 계층을 통해 확장성과 보안성 확보
  • 주문형 코드(Code-On-Demand, 선택 사항): 서버가 클라이언트에 코드를 제공 (자바스크립트 등)

이 중 "통합 인터페이스"가 매우 중요하며, 그 안에 바로 오늘 이야기할 HATEOAS가 포함된다.


HATEOAS, REST의 숨겨진 보석

HATEOAS는 "Hypermedia as the Engine of Application State"의 약자이다. 직역하면 "애플리케이션의 상태에 대한 엔진으로서의 하이퍼미디어"가 된다. 이 이름만으로는 조금 어렵게 느껴질 수 있는데, 쉽게 말해 이런 의미이다.

"클라이언트가 서버로부터 어떤 자원(Resource)에 대한 응답을 받았을 때, 그 응답 안에는 다음으로 할 수 있는 액션(행동)에 대한 정보(하이퍼링크)가 포함되어 있어야 한다."

내가 웹 브라우저를 통해 웹사이트를 탐색하는 과정을 떠올려 본다. 어떤 페이지에 접속하면, 그 페이지에는 다른 페이지로 이동할 수 있는 링크, 특정 기능을 실행할 수 있는 버튼 등이 있다. 나는 이 링크들을 클릭하며 웹사이트를 탐색하고, 애플리케이션의 상태를 변경한다. 즉, 웹 브라우저의 탐색은 하이퍼링크를 통해 이루어지는 "하이퍼미디어 기반"의 상태 전이인 것이다.

Roy Fielding은 RESTful API도 이와 같아야 한다고 말한다. API를 사용하는 클라이언트(웹, 모바일 앱 등)가 API 문서를 일일이 찾아볼 필요 없이, API 응답 자체만으로 다음에 어떤 요청을 보낼 수 있는지 알 수 있어야 한다는 것이다.


HATEOAS의 간단한 예시

일반적인 RESTful API에서 사용자 정보를 조회하는 경우를 생각해 본다.

HATEOAS가 적용되지 않은 예시:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "id": "user123",
    "name": "홍길동",
    "email": "hong@example.com"
}

이 응답만으로는 클라이언트가 이 사용자 정보를 가지고 다음에 무엇을 할 수 있는지 알 수 없다. 사용자를 업데이트할 수 있는지, 삭제할 수 있는지, 아니면 다른 관련 정보가 있는지 알기 위해서는 별도의 API 문서를 참조해야 한다.

HATEOAS가 적용된 예시:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "id": "user123",
    "name": "홍길동",
    "email": "hong@example.com",
    "_links": {
        "self": {
            "href": "/users/user123"
        },
        "update": {
            "href": "/users/user123",
            "method": "PUT"
        },
        "delete": {
            "href": "/users/user123",
            "method": "DELETE"
        },
        "orders": {
            "href": "/users/user123/orders"
        }
    }
}

위 예시에서는 _links라는 필드를 통해 현재 자원(self)의 URI는 물론, 이 사용자를 업데이트하거나 삭제할 수 있는 URI, 그리고 이 사용자의 주문 목록을 조회할 수 있는 URI를 함께 제공하고 있다. 클라이언트는 이 링크들을 동적으로 파싱하여 다음 액션을 결정할 수 있다.


왜 HATEOAS가 중요할까?

  1. 유연성(Flexibility): API 버전이 변경되거나 자원 URI가 바뀌어도 클라이언트는 미리 하드코딩된 URI 대신 응답에 포함된 링크를 사용하므로, 클라이언트 코드를 수정할 필요가 줄어든다.
  2. 탐색 가능성(Discoverability): API 문서를 따로 보지 않아도 응답만으로 API를 탐색하고 사용할 수 있다. 이는 "Self-Descriptive Messages"라는 REST 원칙과도 연결된다.
  3. 결합도 감소(Reduced Coupling): 클라이언트와 서버 간의 강한 결합도를 줄여서, 서버가 API의 구조를 변경하더라도 클라이언트에 미치는 영향을 최소화한다.

물론, HATEOAS를 완벽하게 구현하는 것은 쉽지 않다. API 설계가 복잡해지고, 클라이언트 역시 하이퍼미디어 링크를 파싱하고 처리하는 로직을 추가해야 하기 때문이다. 이 때문에 많은 RESTful API는 HATEOAS를 생략하거나 최소한으로만 적용하는 경우가 많다.

하지만 HATEOAS는 Roy Fielding이 REST를 정의할 때 가장 중요하게 강조한 원칙 중 하나이다. 내가 "RESTful하다"고 부르는 API들이 진정으로 REST의 이념을 따르고 있는지 다시 한번 생각해 보게 만드는 개념이다. 나의 다음 API 설계에서는 HATEOAS를 한 번쯤 적용해 보는 것은 어떨까?

profile
Don't forget Rule No.1

0개의 댓글