プロトコル

HATEOASとは?RESTレベル3の仕組みとHAL・JSON:APIの実装判断を解説

HATEOASとは、APIの応答に「次に実行できる操作へのリンク」を含め、クライアントがそのリンクをたどってアプリケーションの状態を進める設計制約です。注文が未払いなら支払いリンクとキャンセルリンクが並び、出荷済みになればキャンセルリンクが消える。クライアントはステータス文字列を条件分岐せず、届いたリンクの有無で次の操作を決めます。REST全体の設計思想とリソース指向アーキテクチャとRESTの違いは別記事に譲り、ここではHATEOASという単一の制約に絞ります。扱う範囲は、成熟度モデルでの位置づけ、4形式の記述差、実装負担、採用の線引きまでです。

まとめ|HATEOASが買う疎結合と、レベル2で止める現実解の境界線

この制約が売っているのは1つです。サーバがURIの構成を変えても、クライアントを直さずに済む状態。クライアントは初期URIだけを知り、以後の遷移先は応答のリンクから受け取ります。UIのボタン出し分けを分岐で書かずに済む実利もつきます。

対価は小さくありません。サーバはレスポンス生成のたびに権限とリソース状態を評価してリンク集合を組み立てることになり、その集合は利用者ごとに変わるため応答キャッシュと衝突します。最大の問題は、リンクをたどる汎用クライアントが現実にはほとんど書かれていないこと。判断としては、クライアントが複数あって同時更新できない・運用が長期にわたる・状態遷移が業務の主役、この3条件のうち2つ以上が当てはまるときだけ採用し、単一のSPAだけが叩く社内APIには持ち込みません。中間解として、メディアタイプは名乗らず links 配列だけ返す折衷が最も費用対効果に合います。

HATEOASとは|応答に含まれるリンクが次の操作を決める統一インターフェース制約

定義と、RESTでの位置づけを固めます。

HATEOASの読み方と略称が指すハイパーメディア駆動の実体

HATEOASは Hypermedia as the Engine of Application State の頭字語です。日本語では「ヘイトオアス」と読まれることが多いものの、公式に定まった読みはありません。

ここでの「アプリケーション状態」はサーバに保存されたデータではなく、クライアントが今どの操作段階にいるかというセッション上の位置を指します。その位置を進めるエンジンがハイパーメディア、つまり応答に含まれるリンクだという主張です。Roy Fieldingの2000年の学位論文では、統一インターフェースを構成する4制約の1つ(残りはURIによる識別、表現を通じた操作、自己記述的メッセージ)として置かれました。

リンクを持たない応答との比較で見るレスポンスJSONの構造差

差が出るのはレスポンスの中身です。リンクを持たないAPIは注文リソースに idstatusamount を返し、クライアントは statuspending なら支払いボタンを出すという分岐を自前で書きます。遷移可否のルールがクライアント側へ複製された状態です。

HATEOASを満たすAPIは、同じ注文に links_links を添えます。各要素は最低限 rel(この操作が何か)と href(どこを叩くか)を持ち、未払いなら pay と cancel の2本、出荷済みなら track だけが並ぶ。クライアントは配列を見てボタンを描くだけで、遷移ルールを持ちません。

Fieldingが2008年に示したハイパーテキスト駆動の6条件

Fieldingは2008年10月20日の投稿「REST APIs must be hypertext-driven」で、当時REST APIと名乗っていた設計の大半を否定しました。挙げられた条件は6つです。

  • 単一の通信プロトコルに依存しない(URI識別はどのスキームでも許容する)
  • 通信プロトコルそのものへの変更を含まない(既存標準の詳細を補うにとどめる)
  • 記述努力の大半をメディアタイプの定義に費やす
  • 固定のリソース名や階層構造を定義しない(サーバが名前空間を制御する)
  • クライアントにとって意味を持つ「型付きリソース」を置かない
  • 初期URIと標準メディアタイプ以外の事前知識なしに開始できる

実務に効くのは4番目と6番目です。エンドポイント一覧を配布した時点でクライアントはURI構成を事前知識として持つので、多くのAPIドキュメントがそのまま違反にあたります。

Richardson成熟度モデルのレベル3判定と実運用APIがレベル2で止まる理由

位置づけを段階で示したのがRichardson成熟度モデルです。

レベル0から3までの区分と各段階で変わるクライアント側の実装

Leonard RichardsonがQCon 2008で提示し、Martin Fowlerが2010年3月18日の記事で整理しました。段階ごとにクライアントが持つ事前知識の量が変わります。

レベル サーバ側の特徴 クライアント側の実装
0 単一URIへPOSTするRPC様式 本文に操作名を埋める
1 リソース単位にURIを分ける URIを自前で組み立てる
2 HTTPメソッドと状態コードを使う URI規約を事前に持つ
3 応答に遷移リンクを含める 受け取ったリンクをたどる

同記事はFieldingの定義でレベル3がRESTの前提条件だと明記しており、世の「RESTful API」の大半は基準を満たしません。

レベル2で止まるAPIに共通する自社クライアント前提という条件

レベル2で困らないAPIには共通点があります。叩くクライアントが自社製で、サーバと同時にデプロイできること。URI規約はOpenAPIで配布され、変更時は両方を一緒に直せます。この前提が成り立つなら、リンクをたどる仕組みは費用だけが増える。

推進側の「URLにv1を入れる必要がなくなる」という主張も半分しか当たりません。URIは隠せてもレスポンス構造の変更は隠せず、結局メディアタイプ側の版管理が要ります。版番号の表し方はセマンティックバージョニングとAPIバージョニングの運用設計で扱うとおり、URIパス・ヘッダ・メディアタイプのどれを使うかという別の選択です。HATEOASはこの選択を消すのではなく、置き換えるだけです。

PayPalのlinks配列に見る部分的なハイパーメディア採用の実例

現実的な着地点は全面採用ではなく部分採用です。PayPalのREST APIは応答に links 配列を返します。各要素は href が必須、rel が必須、method は省略時GET。リファレンスに実例として載る rel は self・refund・parent_payment で、完全な一覧はIANAのLink Relationship Typesを参照するよう案内されています。

ただしこの形でも「事前知識なしに動く」水準には届きません。refund というrel名の意味も送るべき内容も、開発者がドキュメントを読んで実装するからです。

HAL・JSON:API・Sirenの記述差とレスポンス実例の読み分け

リンクを載せる書式は、複数の仕様が競合したまま決着していません。

HALの_links構造とcurie記法・埋め込みリソースの表現

HAL(Hypertext Application Language)が最も普及した形式です。メディアタイプは application/hal+json。リソース直下の _links にrel名をキー、href を持つオブジェクトを値として並べます。関連リソースを同梱する _embedded で往復回数を減らせ、独自rel名は curie(Compact URI)で名前空間を短縮できます。

仕様としての立ち位置は弱く、IETFの draft-kelly-json-hal は draft-11 が2023年10月19日更新のまま失効しており、2026年8月時点でRFCになっていません。

JSON:API 1.1が規約として固定するlinksとrelationships

JSON:API は v1.1 が2022年9月30日にリリースされ、メディアタイプ application/vnd.api+json はIANAに登録済みです。HALと違い、リンクだけでなく dataattributesrelationshipsincluded といった文書構造まで規定し、ページネーションやフィルタの書式も仕様側で決まっています。

規約が強いぶん自由度は下がり、既存レスポンスからの移行コストは高い。準拠を機械的に検証するなら、JSON Schemaによる構造検証の書き方と組み合わせてCIで落とす形が取れます。

SirenとHAL-FORMSが加えるアクション記述とフォーム定義

HALとJSON:APIが答えないのは「そのリンクへ何を送ればよいか」です。Siren(application/vnd.siren+json)は actions 配列に操作名・メソッド・送信先・入力フィールドまで含めます。HAL-FORMS(application/prs.hal-forms+json)は同じ発想でHALを拡張し、_templates にフォーム定義を載せます。

ここまで来るとサーバが返すのはデータではなく画面定義に近づきます。業務ごとに専用UIを作る受託開発では動機が薄く、採用例も伸びていません。

4形式の比較で見る規約の厳格さ・ツール成熟度・採用判断の目安

規約の強さと標準の生死で並べると、選択肢は実質2つに絞られます。表中のメディアタイプは application/ の接頭辞を省いています。

形式 メディアタイプ 規約の厳格さ 標準の状態
HAL hal+json リンク表現のみ規定 draft-11で失効
HAL-FORMS prs.hal-forms+json フォーム定義まで規定 個人仕様として公開
JSON:API vnd.api+json 文書構造まで規定 v1.1が2022年に確定
Siren vnd.siren+json アクション記述を規定 個人仕様・更新は停滞

組織横断で書式を統一したいならJSON:API、既存レスポンスへリンクだけ足したいならHAL。SirenとHAL-FORMSは、汎用クライアントを作る計画が具体的にある場合を除いて見送ります。

リンク生成の権限連動とキャッシュ設計から見るサーバ側実装の負担

形式を決めた後に効いてくるのが、リンクを組み立てる側のコストです。

権限とリソース状態に応じてリンク集合を出し分ける実装の考え方

リンク集合は固定値ではありません。同じ注文リソースでも、担当者には cancel が見え、閲覧専用ユーザには self だけが返る。状態が shipped に変われば cancel は消えます。

素朴に書くとシリアライザの中で認可チェックが何度も走り、一覧で100件返せばリンク種別×100回の判定です。リンク候補を「rel名・URIビルダ・表示条件関数」の3点セットで宣言し、条件関数が参照する認可情報をリクエスト単位でメモ化してください。判定を1回に畳めば一覧APIでも実用に耐えます。

Spring HATEOAS 3.1系が肩代わりする範囲と残る手作業

Javaではこの領域を Spring HATEOAS が埋めています。2026年8月時点の版は 3.1.1(2026年6月9日リリース)。RepresentationModel を継承したモデルに linkTo(methodOn(...)) でコントローラのメソッドからURIを逆算して差し込め、URIのハードコードを消せます。@EnableHypermediaSupport が受け付けるのは HAL・HAL_FORMS・COLLECTION_JSON・UBER・ALPS で、JSON:APIとSirenはコミュニティ拡張の担当です。

肩代わりされるのはシリアライズとURI生成まで。どのリンクをどの条件で出すかという業務判断は手作業で残り、Java以外なら生成層ごと自前で書く前提の見積もりになります。

レスポンスキャッシュとリンクの鮮度が衝突する場面と回避の手順

見落とされやすいのがキャッシュとの相性です。リンク集合が利用者の権限で変わる以上、その応答は共有キャッシュに置けません。CDNやリバースプロキシに載せた瞬間、閲覧専用ユーザへ担当者向けの cancel リンクが配られる事故が起きます。

  1. 認可に依存する応答には Cache-Control: private を付け、共有キャッシュへの格納を止める
  2. 認証方式でリンクが変わる場合は Vary: Authorization を付け、キャッシュキーを分ける
  3. 状態遷移で消えるリンクを含む応答は max-age を短くし、ETagによる再検証へ寄せる

キャッシュヒット率は確実に落ちます。参照系が支配的なAPIでは損失が利得を上回るため、一覧系だけリンクを省く分離も選択肢です。

OpenAPI定義とハイパーメディア記述の二重管理が生む乖離

OpenAPIはパスとメソッドを列挙する仕様で、URI構成を事前に配布する道具です。HATEOASの前提とは逆を向いています。それでもOpenAPIを捨てられないため、パス定義とリンク定義の両方を書く二重管理になります。

典型的な乖離は、新しいrelを実装へ足したのにOpenAPIのスキーマ例へ反映されず、クライアント担当が存在を知らないまま実装が進むパターンです。rel名の一覧を単一の定数定義に集約し、スキーマ例とテストの両方をそこから生成すれば防げます。非同期側も記述仕様が分かれるため、AsyncAPIとOpenAPIの違いとイベント駆動APIの設計を踏まえ、契約の管理先を先に決めてください。

クライアントがリンクを読まない構造とHATEOASが普及しない原因

広がらなかった理由は、クライアント側の事情にあります。

URLの組み立てを捨てられないクライアント実装の現実的な事情

SPAもモバイルアプリも、画面遷移が先に決まっています。注文詳細から返金画面へ進むルートはデザイン段階で確定しており、そこへ「サーバが refund リンクを返してきたら遷移可能」という間接層を挟んでも画面構造は変わりません。

コード量も逆転しない。URIテンプレートに注文IDを埋める処理は1行、リンク配列から rel を探して見つからなければボタンを隠す処理は探索と分岐で数行です。

rel名の標準化不足が汎用クライアントを成立させない構図と実害

本質的な原因はここです。IANAのLink Relation Typesに登録されているのは self・next・prev・edit・describedby といった汎用語で、業務の操作を表す語彙は含まれません。承認・返金・出荷指示といったrelは各社が独自に命名します。

すると、クライアントは「approve というrelが来たら承認ボタンを出す」と事前に知っている必要がある。事前知識ゼロで動くという目標は、この時点で達成できません。目標が半分しか届かないのにコストは全部かかる、この費用対効果の悪さが普及を止めました。

GraphQLとgRPCの普及で問題設定が置き換わった10年の経緯

2015年に公開されたGraphQLとgRPCが、同じ問題へ別の答えを出したことも大きい。GraphQLはクライアントが必要なフィールドを問い合わせる形で過不足を解消し、gRPCはProtocol Buffersのスキーマからクライアントコードを生成して型の不整合を消しました。

いずれもスキーマという事前知識を前提にしており、Fieldingの理想とは逆方向です。それでも「クライアントとサーバの変更を切り離す」課題は解けてしまった。理想を満たさない解が課題を解いたとき、理想側は選ばれません。

HATEOASを採用する条件と、レベル2で止めるべき場面の線引き

ここからは判断です。全採用か不採用かの二択ではなく、条件で切り分けます。

採用が効く3条件:多クライアント・長期運用・状態遷移の主役化

採用が回収できるのは次の3条件です。第一に、APIを叩くクライアントが複数あり、そのすべてを自社で同時更新できないこと。取引先や外部ベンダー実装のクライアントが混ざる公開APIが該当します。第二に、5年以上の運用が見込まれ、URI設計を変える公算が高いこと。第三に、承認フロー・決済・予約のように状態遷移が業務の中心にあることです。

3条件のうち2つ以上が当てはまるなら入れる。1つ以下なら入れません。設計レビューで数えて決めます。

見送る場面は単一SPA・社内専用API・短命プロダクトの3類型

逆に、次の3類型では採用しません。フロントが1つのSPAだけで同一リポジトリに同居しているケースは、サーバと画面を同じスプリントで直せるため疎結合の対価が無駄になります。社内専用APIで利用者を把握できているケースも同じ。3つ目は2年以内に作り直す短命プロダクトで、URI変更のコストが発生する前に寿命が来ます。

「将来的に外部公開するかもしれない」を理由に入れるのは過剰で、公開が決まった時点でリンク層を足す方が安く済みます。

links配列だけ返して規約は決め打ちにする段階導入の折衷案

費用対効果が最も良いのは中間解です。HALやJSON:APIのメディアタイプは名乗らず、通常のJSONレスポンスに links 配列を1つ足すだけ。要素は rel・href・method の3項目に固定し、rel名は自社の用語集で決め打ちする。クライアントは「そのrelが配列にあるか」でボタンを出し分けます。

これで消えるのは、遷移可否ルールがサーバとクライアントへ二重実装される問題です。なお、リンクをたどって実行するPOSTは通信断で再送されやすく、二重実行の対策が別途要る。Idempotency-Keyによる二重実行の防ぎ方と組み合わせて設計してください。

受託開発でAPI設計方式を決める判断順序と発注側との合意形成

外部にAPI開発を委託する場合、方式の議論を実装フェーズへ持ち込むと手戻りになります。確認する順序は、クライアントの数と更新権限、想定運用年数、状態遷移の複雑さの3つ。要件定義で発注側と詰めれば、レベル2で止めるか折衷案を入れるかは自動的に決まります。全体の組み立てはREST・認証・エラー処理を含むAPI連携の実装手順にまとめました。

設計方針の判断や、既存APIへリンク層を足す改修の見積もりはAPI開発・システム連携の支援で相談を受け付けています。既存レスポンスの構造と利用クライアントの一覧があれば、採用可否まで詰められます。

よくある質問

HATEOASの読み方や、実装可否の判断でよく挙がる質問をまとめます。

HATEOASの読み方は何ですか?

日本語では「ヘイトオアス」と読まれることが多く、「ヘイティオアス」と表記される例もあります。公式に定められた読みはないため、社内ドキュメントでは略称のまま HATEOAS と書き、初出で正式名称を併記する形が誤解を招きません。

HATEOASを実装しないとRESTと呼べないのですか?

Fieldingの定義に照らせば、ハイパーメディア制約を満たさない設計はRESTではありません。Richardson成熟度モデルを整理したMartin Fowlerの記事も、レベル3がRESTの前提条件だと明記しています。実務ではレベル2を指してRESTと呼ぶ慣行が定着したため、社外向けの仕様書では「RESTスタイルのHTTP API」と書き、レベル3を満たすかどうかを別記するのが安全です。

HALとJSON:APIはどちらを選べばよいですか?

組織横断で複数チームがAPIを作り、書式のばらつきを仕様で封じたいならJSON:APIです。v1.1が2022年9月に確定し、メディアタイプもIANA登録済みです。既存のJSONレスポンスを維持したままリンクだけ足したいならHALが軽い。ただしHALのドラフトはdraft-11が2023年10月更新のまま失効しており、後ろ盾は弱い点を織り込んでください。

HATEOASとOpenAPIは併用できますか?

併用自体は可能ですが、思想は衝突します。OpenAPIはパスとメソッドを事前に配布する仕様で、URI構成を知らせない前提とは逆向きだからです。実務では両方を書く二重管理になり、relを追加した際に反映漏れが起きます。rel名の一覧を単一の定数定義に集約し、スキーマ例と契約テストをそこから生成すれば、乖離を機械的に防げます。

Spring以外の言語にHATEOASの実装ライブラリはありますか?

形式ごとのシリアライザは各言語に存在するものの、フレームワーク統合の成熟度はJavaのSpring HATEOASが突出しています。3.1.1がHAL・HAL-FORMS・Collection+JSON・UBER・ALPSを標準サポートし、JSON:APIとSirenは spring-hateoas-jsonapi・spring-hateoas-siren というコミュニティ拡張が担います。Java以外を採用する場合は、リンク生成層を自前で実装する前提で工数を見積もってください。

関連記事

資料請求

RELATED POSTS 関連記事