사전 하이퍼미디어
개념

하이퍼미디어

gabury1고친 사람 github-actions[bot]

하이퍼미디어는 읽는 쪽이 링크를 따라 다음 내용으로 건너가게 해 주는 내용입니다. 글뿐 아니라 그림과 입력 양식도 이 링크로 이어집니다. 웹 페이지가 가장 흔한 하이퍼미디어입니다. 서버 개발에서는 응답에 「다음에 할 수 있는 일」을 링크로 실어 보내는 방식을 이 이름으로 부릅니다.

쉽고 빠른 이해

하이퍼미디어는 다음에 갈 곳을 링크로 품고 있는 내용입니다. 주문 조회 응답에 「이 주문 취소하기」 링크가 붙어 오면, 받는 쪽은 지금 취소할 수 있다는 것과 어디로 요청할지를 함께 압니다.

링크가 없으면 받는 쪽이 주소 규칙과 업무 규칙을 미리 외워 둬야 합니다. 서버가 주소를 바꾸거나 취소 조건을 고치면 받는 쪽 코드도 함께 고쳐야 합니다.

어떻게 도는가:

  1. 받는 쪽은 처음 들어갈 주소 하나만 압니다
  2. 응답에 담긴 링크 가운데 하려는 일에 맞는 것을 고릅니다
  3. 그 링크를 따라가 새 응답을 받습니다. 거기서 다시 고릅니다

대가가 있습니다. 응답마다 링크를 싣느라 응답이 커집니다. 받는 쪽은 링크마다 붙은 관계 이름이 무슨 뜻인지를 여전히 미리 알아야 합니다. 그래서 받는 쪽 프로그램을 남이 여럿 만들어 쓰거나, 상태에 따라 다음에 할 일이 자주 갈릴 때 값을 합니다. 서버와 받는 쪽을 한 팀이 같이 고쳐 내보내면 수고가 더 큽니다.

상세

처음 가 본 큰 병원에서는 건물 지도를 외우고 들어가지 않습니다. 접수창구에서 받은 종이에 다음에 갈 곳이 적혀 있습니다. 그곳에 가면 또 다음 갈 곳을 알려 줍니다. 길을 아는 것은 환자가 아니라 병원입니다.

하이퍼텍스트는 다른 글로 건너가는 링크를 품은 글입니다. 하이퍼미디어는 이 생각을 글 밖으로 넓힌 것입니다. 그림 한 장이나 입력 양식 하나도 링크의 출발점이 되고 도착점이 됩니다.

뉴스 사이트를 떠올리면 됩니다. 기사 속 낱말을 누르면 다른 기사로 갑니다. 사진을 누르면 큰 사진으로 갑니다. 검색창에 글자를 넣고 누르면 결과 페이지로 갑니다.

이 말은 두 곳에서 씁니다. 하나는 사람이 링크를 눌러 돌아다니는 웹 문서입니다. 다른 하나는 서버가 돌려주는 응답에 링크를 실어 프로그램이 따라가게 하는 API(Application Programming Interface, 응용 프로그래밍 인터페이스) 설계입니다. 아래는 뒤쪽 뜻을 중심으로 풉니다.

하이퍼미디어 컨트롤

하이퍼미디어가 받는 쪽에 알려 주는 것은 둘입니다. 어디로 갈 수 있는지, 그리고 무엇을 보낼 수 있는지입니다. 앞의 것은 링크가 맡습니다. 뒤의 것은 폼이 맡습니다. 이 둘을 묶어 하이퍼미디어 컨트롤이라고 부릅니다.

링크는 갈 주소 하나를 담습니다. 그 주소가 지금 내용과 어떤 사이인지도 함께 적을 수 있습니다.

그 사이를 가리키는 이름을 관계 이름이라고 부릅니다. 「다음 페이지」나 「작성자」나 「이 글 자신」 같은 이름입니다. 받는 쪽은 관계 이름을 보고 여러 링크 가운데 하나를 고릅니다.

폼은 링크보다 한 걸음 더 나아갑니다. 어느 주소로 보낼지에 더해, 어떤 종류의 요청으로 보낼지와 어떤 칸을 채워 보낼지까지 적습니다. 요청의 종류는 조회인지 변경인지를 가르는 요청 메서드입니다.

웹 페이지를 적는 언어인 HTML(HyperText Markup Language, 하이퍼텍스트 마크업 언어)로 두 컨트롤을 적으면 이렇습니다.

HTML
<a href="/orders/42">주문 42 보기</a>

<form method="post"
      action="/orders/42/cancel">
  <input name="reason">
  <button>주문 취소</button>
</form>

위의 a 줄이 링크입니다. href 가 갈 주소입니다. 아래 form 은 /orders/42/cancel 로 POST 요청을 보내라고 알려 줍니다. 보낼 때는 reason 칸에 적은 글자를 함께 싣습니다.

사이트를 모르고도 도는 브라우저

브라우저는 쇼핑몰이 무엇을 파는지 모릅니다. 주문을 어떻게 취소하는지도 모릅니다. 브라우저가 아는 것은 HTML 을 읽는 규칙뿐입니다. 링크는 누르면 따라갑니다. 폼은 채워서 보냅니다.

그런데도 사람은 브라우저로 주문을 취소합니다. 취소 버튼과 보낼 주소를 서버가 페이지에 담아 보냈기 때문입니다. 무엇을 할 수 있는지는 페이지가 알려 줍니다. 브라우저는 그 안내를 따를 뿐입니다.

이 덕에 서버는 브라우저를 건드리지 않고 사이트를 바꿀 수 있습니다. 주소를 바꾸면 새 페이지에 새 주소를 적으면 됩니다. 기능을 더하면 새 링크를 하나 더 적으면 됩니다. 길을 아는 쪽이 서버 하나뿐이라서 바꿀 곳도 서버 하나입니다.

REST 가 요구하는 하이퍼미디어

REST(Representational State Transfer, 표현 상태 전이)는 웹이 이렇게 도는 방식을 서버 사이의 통신에도 쓰자는 설계 제약의 묶음입니다. 그 가운데 하나가 「애플리케이션 상태의 엔진으로서의 하이퍼미디어」입니다. 줄여서 HATEOAS(Hypermedia As The Engine Of Application State)라고 적습니다.

애플리케이션 상태는 클라이언트(지금까지 받는 쪽이라 부른 프로그램)가 지금 일의 어느 단계에 와 있는지를 말합니다. 주문 목록을 보는 중인지, 주문 하나를 열어 본 참인지, 결제 바로 앞인지가 그 예입니다.

이것은 자원의 상태와 다릅니다. 자원은 주문 하나처럼 주소를 붙여 가리키는 대상입니다. 그 상태는 서버가 들고 있습니다. 주문이 「결제 완료」인지 「배송 중」인지가 자원의 상태입니다.

서버는 자원의 지금 모습을 HTML 같은 형식으로 적어 응답 본문에 싣습니다. 이 응답 본문을 REST 에서는 표현이라고 부릅니다. 주문 42의 표현이라면 주문 번호와 상태, 그리고 다음에 갈 링크가 들어 있습니다.

「엔진」은 이 단계를 옮기는 힘이 하이퍼미디어에서 나온다는 뜻입니다. 클라이언트는 서버가 보낸 표현 안의 링크와 폼만 따라 다음 단계로 넘어갑니다. 다음 단계로 갈 길을 클라이언트 코드가 스스로 만들지 않습니다.

그래서 클라이언트가 미리 아는 주소는 입구 하나입니다. 입구는 처음 요청을 보낼 URI(Uniform Resource Identifier, 통합 자원 식별자)입니다. 나머지 주소는 전부 응답을 받으면서 알게 됩니다.

아래 그림은 입구에서 주문 취소까지 가는 길입니다.

sequenceDiagram
    participant 클라이언트
    participant 서버
    클라이언트->>서버: 입구 주소로 요청
    서버-->>클라이언트: 주문 목록 링크
    클라이언트->>서버: 주문 목록 링크를 따라감
    서버-->>클라이언트: 주문마다 링크
    클라이언트->>서버: 주문 42 링크를 따라감
    서버-->>클라이언트: 주문 42와 취소 링크
    클라이언트->>서버: 취소 링크대로 요청

JSON 응답에 싣는 링크

서버 사이의 응답은 대개 JSON(JavaScript Object Notation, 자바스크립트 객체 표기법)으로 적습니다. JSON 에는 링크라는 개념이 없습니다. 값에 주소를 적어 넣어도 JSON 을 읽는 쪽에게 그것은 글자일 뿐입니다. HTML 은 a 가 링크라고 정해 두었습니다. JSON 에는 그런 약속이 없습니다.

그래서 JSON 응답에 링크를 실으려면 적는 방식을 따로 맞춰야 합니다. 응답 본문이 어떤 형식인지를 알리는 이름을 미디어 타입이라고 합니다. 그중 링크 표기까지 정해 둔 미디어 타입을 골라 쓰기도 합니다. 팀 안에서 필드 이름을 정하기도 합니다.

아래는 팀이 links 라는 필드에 링크를 모으기로 정한 경우입니다. 결제만 끝난 주문 42를 조회했습니다.

JSON
{
  "id": 42,
  "status": "결제 완료",
  "links": {
    "self": { "href": "/orders/42" },
    "cancel": {
      "href": "/orders/42/cancel",
      "method": "POST"
    }
  }
}

self 와 cancel 이 관계 이름입니다. self 는 이 주문 자신의 주소입니다. cancel 은 취소 요청을 보낼 주소와 방법입니다. 같은 주문이 배송을 떠난 뒤에 다시 조회하면 응답이 달라집니다.

JSON
{
  "id": 42,
  "status": "배송 중",
  "links": {
    "self": { "href": "/orders/42" }
  }
}

cancel 링크가 사라졌습니다. 클라이언트는 링크가 있을 때만 취소 버튼을 띄우면 됩니다. 「배송 전이면 취소할 수 있다」는 규칙을 클라이언트가 따로 들고 있지 않아도 됩니다. 규칙은 서버에만 있습니다.

링크를 본문 대신 HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 프로토콜) 응답 헤더에 싣는 방법도 있습니다. Link 헤더에 주소와 관계 이름을 함께 적습니다. 목록을 여러 페이지로 나눠 줄 때 다음 페이지 주소를 next 라는 관계로 알려 주는 쓰임이 흔합니다.

관계 이름

하이퍼미디어를 써도 클라이언트가 미리 알아야 하는 것이 사라지지는 않습니다. cancel 이 취소라는 뜻인지는 클라이언트가 알고 있어야 그 링크를 고를 수 있습니다.

하이퍼미디어가 하는 일은 미리 알 것을 바꾸는 것입니다. 주소를 짜는 규칙과 업무 규칙 대신, 관계 이름과 응답 형식만 알면 되게 합니다. self 나 next 처럼 여러 곳에서 두루 쓰는 이름은 표준 기구가 관리하는 공용 목록에 올라 있어서 누구나 같은 뜻으로 씁니다.

링크 없는 API 와의 차이

흔히 보는 API 는 응답에 링크를 싣지 않습니다. 대신 주소 규칙을 문서로 알려 줍니다. 클라이언트는 그 규칙으로 주소를 조립합니다. 두 방식에서 바뀌는 것을 나란히 놓으면 이렇습니다.

링크 없는 API 하이퍼미디어 API
클라이언트가 미리 아는 것 모든 주소 규칙과 업무 규칙 입구 주소 · 관계 이름 · 응답 형식
서버가 주소를 바꾸면 클라이언트 코드도 고칩니다 응답의 링크만 바뀝니다
취소 조건이 바뀌면 클라이언트의 조건문도 고칩니다 서버가 링크를 넣고 빼는 조건만 고칩니다
응답 크기 데이터만 싣습니다 링크만큼 커집니다
설계할 것 주소 규칙 주소 규칙에 더해 관계 이름과 링크 표기

이 이점은 클라이언트가 링크를 따라갈 때만 생깁니다. 클라이언트가 링크를 무시하고 주소를 코드에 적어 두면, 서버가 링크를 바꿔도 클라이언트는 옛 주소로 요청합니다. 그러면 링크는 응답 크기만 늘립니다.

쓰는 경우와 안 쓰는 경우

하이퍼미디어가 덜어 주는 것은 서버와 클라이언트를 따로 고치는 비용입니다. 그래서 그 비용이 클 때 값을 합니다. 남이 만든 클라이언트가 많아서 한꺼번에 고치게 할 수 없는 API 가 그렇습니다. 주문이나 결제처럼 상태에 따라 다음에 할 수 있는 일이 자주 갈리는 흐름도 그렇습니다.

서버와 클라이언트를 한 팀이 같이 고치고 같이 배포하면 사정이 다릅니다. 주소를 바꿀 때 양쪽을 함께 고치면 되니, 링크가 덜어 주는 일이 적습니다. 이때는 링크를 싣고 관계 이름을 설계하는 수고가 더 크게 남습니다.

관련 항목

하이퍼미디어를 이루는 구성 요소

하이퍼텍스트 · 하이퍼링크 · HTML 폼 · 하이퍼미디어 컨트롤 · 링크 관계 · URI · URL

하이퍼미디어를 제약으로 둔 설계 원칙

REST · HATEOAS · 통일된 인터페이스 · 자기 서술적 메시지 · 무상태 · 자원 · 자원 지향 설계 · API 설계

하이퍼미디어를 담아 나르는 형식

HTML · JSON · 미디어 타입 · 표현 · HAL · Siren · JSON-LD · Atom · Content-Type

링크를 실어 나르는 HTTP 요소

HTTP · 요청 메서드 · Link 헤더 · 헤더 · 콘텐츠 협상 · 상태 코드

링크를 따라 움직이는 클라이언트

브라우저 · 클라이언트 · 웹 크롤러 · htmx · API 클라이언트

링크 대신 규칙을 미리 나눠 갖는 API 방식

RPC · gRPC · GraphQL · OpenAPI · 엔드포인트 · SOAP

하이퍼미디어가 줄이려는 결합과 변경 비용

결합도 · 하위 호환 · API 버전 관리 · 페이지네이션 · 상태 머신 · 워크플로

하이퍼미디어가 비롯된 배경

월드 와이드 웹 · 하이퍼텍스트 시스템 · Roy Fielding · W3C

다른 이름: hypermedia · Hypermedia