본문 바로가기
Artificial Intelligence/60. Python

[PYTHON] RESTful API 설계 시 HATEOAS를 도입해야 하는 3가지 이유와 구현 방법

by Papa Martino V 2026. 3. 20.
728x90

HATEOAS
HATEOAS (Hypermedia As The Engine Of Application State)

 

현대 소프트웨어 아키텍처에서 REST(Representational State Transfer)는 가장 보편적인 통신 규약입니다. 하지만 우리가 진정한 의미의 RESTful API를 구축하고 있는지에 대해서는 늘 의문이 따릅니다. REST의 창시자인 로이 필딩(Roy Fielding)은 "HATEOAS를 만족하지 않는 API는 REST API라고 부를 수 없다"고 단언했습니다. 오늘 이 글에서는 파이썬 환경에서 HATEOAS를 고려해야 하는 실무적인 이유와 이를 구현하는 구체적인 기술적 해법을 심도 있게 다룹니다.


1. HATEOAS란 무엇인가? 개념과 필요성

HATEOAS(Hypermedia As The Engine Of Application State)는 애플리케이션의 상태 전이를 하이퍼미디어를 통해 제어한다는 개념입니다. 클라이언트는 서버로부터 받은 응답 내에 포함된 링크를 통해 다음 단계로 어떤 행위가 가능한지 동적으로 파악합니다.

왜 HATEOAS인가?

  • 클라이언트와 서버의 약결합(Loose Coupling): 클라이언트는 API 엔드포인트 URI를 미리 다 알 필요가 없습니다.
  • 동적 인터페이스: 사용자의 권한이나 리소스 상태에 따라 가능한 작업(수정, 삭제 등)을 서버가 실시간으로 필터링하여 응답에 포함할 수 있습니다.
  • 자가 설명적(Self-descriptive) 메시지: API 명세서를 일일이 찾아보지 않아도 응답 데이터 자체로 다음 행동을 유추할 수 있습니다.

2. REST 성숙도 모델과 HATEOAS의 위치

레너드 리차드슨(Leonard Richardson)이 제시한 REST 성숙도 모델에 따르면, HATEOAS는 가장 높은 단계인 Level 3에 해당합니다.

단계 (Level) 명칭 핵심 특징 도입 필요성
Level 0 The Swamp of POX HTTP를 단순 전송 수단으로만 사용 (RPC 방식) 매우 낮음
Level 1 Resources 개별 리소스에 대한 고유 식별자(URI) 도입 기초적인 수준
Level 2 HTTP Verbs HTTP 메서드(GET, POST, PUT, DELETE)를 용도에 맞게 사용 일반적인 API 수준
Level 3 HATEOAS 하이퍼미디어 컨트롤을 통한 상태 전이 지원 고도화된 서비스 필수

3. 파이썬(Flask/FastAPI)에서 HATEOAS 구현 시 발생하는 차이점과 해결책

파이썬 생태계에서 API를 개발할 때 HATEOAS를 무조건 도입하기에는 몇 가지 현실적인 제약이 따릅니다. 이를 해결하기 위한 전략적 접근이 필요합니다.

문제점 1: 페이로드의 비대화

데이터 외에 링크 정보가 포함되므로 응답 데이터의 크기가 커집니다. 이는 모바일 환경에서 오버헤드가 될 수 있습니다.

해결 방법: 필요한 경우에만 ?links=true와 같은 쿼리 파라미터를 통해 선택적으로 하이퍼미디어를 제공하도록 설계합니다.

문제점 2: 클라이언트 구현의 복잡성

단순히 URL을 하드코딩하던 클라이언트 개발자에게는 링크 기반의 동적 처리가 낯설 수 있습니다.

해결 방법: HAL(Hypertext Application Language) 표준 규격을 준수하여 공통 라이브러리를 사용할 수 있는 환경을 제공합니다.


4. [Sample Example] Python Flask를 이용한 HATEOAS 적용 코드

다음은 사용자의 주문 상태에 따라 다음 가능한 액션(취소, 결제)을 링크로 제공하는 간단한 파이썬 예제입니다.

from flask import Flask, jsonify, url_for

app = Flask(__name__)

@app.route('/orders/<int:order_id>', methods=['GET'])
def get_order(order_id):
    # 실제 환경에서는 DB에서 데이터를 가져옵니다.
    order_status = "PENDING" 
    
    order_data = {
        "order_id": order_id,
        "status": order_status,
        "product": "MacBook Pro M3",
        "amount": 3500000,
        "_links": {
            "self": {"href": url_for('get_order', order_id=order_id, _external=True)},
            "all_orders": {"href": url_for('list_orders', _external=True)}
        }
    }

    # 상태에 따른 동적 링크 생성 (HATEOAS의 핵심)
    if order_status == "PENDING":
        order_data["_links"]["payment"] = {"href": f"/orders/{order_id}/pay", "method": "POST"}
        order_data["_links"]["cancel"] = {"href": f"/orders/{order_id}/cancel", "method": "DELETE"}
    
    return jsonify(order_data)

@app.route('/orders')
def list_orders():
    return jsonify({"message": "Order list endpoint"})

if __name__ == '__main__':
    app.run(debug=True)

5. 결론: HATEOAS, 꼭 고려해야 할까?

결론부터 말씀드리면, "서비스의 생명주기가 길고 클라이언트가 다변화될 가능성이 높다면 반드시 고려해야 한다"입니다. API의 변경이 잦은 스타트업 환경에서는 클라이언트 배포 없이 서버의 응답만으로 UI의 버튼 활성화 여부 등을 제어할 수 있는 HATEOAS가 엄청난 유지보수 이점을 제공합니다. 다만, 내부 시스템끼리 통신하는 마이크로서비스(MSA) 환경이거나 극한의 성능이 요구되는 곳에서는 오버헤드를 고려하여 부분적으로 도입하는 지혜가 필요합니다.


6. 출처 및 참고 문헌

  • Fielding, R. T. (2000). Architectural Styles and the Design of Network-based Software Architectures. University of California, Irvine.
  • Richardson, L., & Ruby, S. (2007). RESTful Web Services. O'Reilly Media.
  • Python Flask Official Documentation - Context Helpers.
  • HAL (Hypertext Application Language) Draft Specification.
728x90