REST APIはHATEOASハイパーメディアリンクを実装すべきか?

Ashley Innocent

Ashley Innocent

13 3月 2026

REST APIはHATEOASハイパーメディアリンクを実装すべきか?

REST APIはHATEOASハイパーメディアリンクを実装すべきか?

TL;DR(要するに)

HATEOAS(Hypermedia as the Engine of Application State)は理論的には優雅ですが、実用上は複雑です。ほとんどのAPIは完全なHATEOASをスキップし、ページネーション、関連リソース、アクションのために選択的にハイパーメディアリンクを使用しています。Modern PetstoreAPIは、クライアントに完全にハイパーメディア駆動であることを強制することなく、実用的なハイパーメディアリンクを実装しています。

はじめに

あなたはREST APIの設計について読んでいます。そこでHATEOAS(Hypermedia as the Engine of Application State)に出くわしました。説明にはこうあります:「クライアントはURLをハードコードするのではなく、ハイパーメディアリンクを通じて全てのアクションを発見すべきです。」

あなたはこう考えます:「それは複雑そうだ。実際にこんなことをしている人がいるのだろうか?」

答えは「ほとんどそうではない」です。HATEOASは、RESTの制約の中で最もスキップされるものです。RESTを考案したロイ・フィールディングはそれが不可欠だと言いますが、ほとんどのAPI設計者は非実用的だと述べています。その結果、ほとんどの「REST」APIは、フィールディングの定義によると真のRESTfulではありません。

Modern PetstoreAPIは実用的なアプローチをとっています。つまり、価値をもたらす場所(ページネーション、関連リソース、アクション)でハイパーメディアリンクを使用しますが、クライアントに完全にハイパーメディア駆動であることを強制しません。

💡
REST APIを構築またはテストしている場合、Apidogはハイパーメディアリンクのテスト、リンク形式の検証、APIが有用なナビゲーションを提供していることの確認に役立ちます。リンクの正確性を検証し、ハイパーメディア駆動のワークフローをテストできます。
ボタン

このガイドでは、HATEOASとは何か、なぜそれが議論の的になっているのか、そしてModern PetstoreAPIを参考に実用的なハイパーメディアリンクを実装する方法を学びます。

HATEOASとは何か?

HATEOASは、クライアントがAPIの機能性をドキュメントではなくハイパーメディアリンクを通じて発見すべきだとするRESTの制約です。

概念

URLをハードコードする代わりに:

// Client hardcodes URLs
const response = await fetch('https://petstoreapi.com/v1/pets/123');
const pet = await response.json();

// Client knows the URL structure
await fetch(`https://petstoreapi.com/v1/pets/${pet.id}/orders`);

クライアントはレスポンスのリンクをたどります:

// Client starts at root
const root = await fetch('https://petstoreapi.com/v1');
const rootData = await root.json();

// Client follows link to pets
const petsUrl = rootData._links.pets.href;
const pets = await fetch(petsUrl);
const petsData = await pets.json();

// Client follows link to specific pet
const petUrl = petsData._links.self.href;
const pet = await fetch(petUrl);
const petData = await pet.json();

// Client follows link to orders
const ordersUrl = petData._links.orders.href;
const orders = await fetch(ordersUrl);

理論

HATEOASを使用すると:

1. クライアントはURLをハードコードしない

URLはクライアントを壊すことなく変更できます。サーバーがURL構造を制御します。

2. クライアントは機能を発見する

リンクが存在すれば、そのアクションは利用可能です。存在しない場合、それは利用できない(またはこのユーザーには許可されていない)ことを意味します。

3. APIは自己文書化される

クライアントは、ウェブサイトを閲覧するように、リンクをたどってAPIを探索します。

例:完全なHATEOASレスポンス

{
  "id": "019b4132-70aa-764f-b315-e2803d882a24",
  "name": "Fluffy",
  "species": "CAT",
  "status": "AVAILABLE",
  "_links": {
    "self": {
      "href": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24"
    },
    "update": {
      "href": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24",
      "method": "PUT"
    },
    "delete": {
      "href": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24",
      "method": "DELETE"
    },
    "orders": {
      "href": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24/orders"
    },
    "adopt": {
      "href": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24/adopt",
      "method": "POST"
    }
  }
}

クライアントはURLパターンを知る必要はありません。リンクをたどるだけです。

HATEOASに関する議論

HATEOASは、理論と実践が乖離しているため、議論の的となっています。

HATEOASを支持する意見

1. 疎結合

クライアントはURL構造に依存しません。サーバーはクライアントを壊すことなくURLを変更できます。

2. 発見性

クライアントはドキュメントを読むことなくAPIを探索できます。

3. ステート駆動型アクション

リンクは利用可能なアクションを示します。ペットが引き取られた場合、「adopt」リンクは表示されなくなります。

4. 真のREST

ロイ・フィールディングは、HATEOASがRESTにとって不可欠であると述べています。それがなければ、RESTを行っていることにはなりません。

HATEOASに反対する意見

1. 複雑さ

クライアントはハイパーメディア解析ロジックを必要とします。シンプルなHTTPクライアントが複雑なステートマシンになってしまいます。

2. パフォーマンス

クライアントはURLを発見するために複数のリクエストを行います。直接URLにアクセスする方が高速です。

3. デバッグの難しさ

リンクをたどることでデバッグが難しくなります。単純にcurlでURLを叩くわけにはいかず、リンクの連鎖をたどる必要があります。

4. ツールが不十分

ほとんどのHTTPクライアント、テストツール、ドキュメントジェネレーターは、ハードコードされたURLを前提としています。

5. 誰もやっていない

GitHub、Stripe、Twilio、Twitterなど、主要なAPIは完全なHATEOASを使用していません。彼らがそれを必要としないなら、あなたも必要でしょうか?

現実

ほとんどのAPIは「REST」だと主張しますが、HATEOASをスキップしています。これらは実際には「HTTP API」または「RESTライクなAPI」です。真のREST(HATEOASを含む)は稀です。

実用的なハイパーメディアリンク

完全なHATEOASの代わりに、価値をもたらす場所でハイパーメディアリンクを使用しましょう。

1. ページネーションリンク

問題: クライアントがページネーションURLを構築する必要がある。

解決策: 次/前のリンクを提供する。

{
  "data": [...],
  "pagination": {
    "page": 2,
    "limit": 20,
    "totalPages": 10
  },
  "links": {
    "self": "https://petstoreapi.com/v1/pets?page=2&limit=20",
    "first": "https://petstoreapi.com/v1/pets?page=1&limit=20",
    "prev": "https://petstoreapi.com/v1/pets?page=1&limit=20",
    "next": "https://petstoreapi.com/v1/pets?page=3&limit=20",
    "last": "https://petstoreapi.com/v1/pets?page=10&limit=20"
  }
}

利点: クライアントはページネーションURLを構築せず、リンクをたどる。

2. 関連リソースリンク

問題: クライアントが関連リソースのURLパターンを知る必要がある。

解決策: 関連リソースへのリンクを提供する。

{
  "id": "019b4132-70aa-764f-b315-e2803d882a24",
  "name": "Fluffy",
  "_links": {
    "self": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24",
    "orders": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24/orders",
    "owner": "https://petstoreapi.com/v1/users/019b4127-54d5-76d9-b626-0d4c7bfce5b6"
  }
}

利点: クライアントはドキュメントなしで関連リソースを発見する。

3. アクションリンク

問題: クライアントが利用可能なアクションを知る必要がある。

解決策: 利用可能なアクションのリンクを提供する。

{
  "id": "019b4132-70aa-764f-b315-e2803d882a24",
  "status": "AVAILABLE",
  "_links": {
    "adopt": {
      "href": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24/adopt",
      "method": "POST"
    }
  }
}

もしペットがすでに引き取られている場合:

{
  "id": "019b4132-70aa-764f-b315-e2803d882a24",
  "status": "ADOPTED",
  "_links": {
    // No "adopt" link - action not available
  }
}

利点: リンクは状態に基づいて利用可能なアクションを示す。

4. カーソルベースのページネーション

問題: クライアントがカーソルURLを構築する必要がある。

解決策: 不透明な次/前のURLを提供する。

{
  "data": [...],
  "links": {
    "next": "https://petstoreapi.com/v1/pets?cursor=eyJpZCI6IjAxOWI0MTMyIn0"
  }
}

利点: クライアントはカーソルを解析せず、リンクをたどる。

Modern PetstoreAPIがハイパーメディアをどのように利用しているか

Modern PetstoreAPIは選択的なハイパーメディアリンクを使用しています。

ページネーションリンク

全てのコレクションエンドポイントにはページネーションリンクが含まれています:

GET /v1/pets?limit=20

{
  "data": [...],
  "pagination": {
    "limit": 20,
    "hasMore": true
  },
  "links": {
    "self": "https://petstoreapi.com/v1/pets?limit=20",
    "next": "https://petstoreapi.com/v1/pets?cursor=eyJpZCI6IjAxOWI0MTMyIn0&limit=20"
  }
}

関連リソースリンク

リソースのレスポンスには関連リソースへのリンクが含まれています:

GET /v1/pets/019b4132-70aa-764f-b315-e2803d882a24

{
  "id": "019b4132-70aa-764f-b315-e2803d882a24",
  "name": "Fluffy",
  "ownerId": "019b4127-54d5-76d9-b626-0d4c7bfce5b6",
  "_links": {
    "self": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24",
    "owner": "https://petstoreapi.com/v1/users/019b4127-54d5-76d9-b626-0d4c7bfce5b6",
    "orders": "https://petstoreapi.com/v1/pets/019b4132-70aa-764f-b315-e2803d882a24/orders"
  }
}

完全なHATEOASはなし

Modern PetstoreAPIは、クライアントがハイパーメディア駆動であることを要求しません。クライアントは以下のことができます:

オプション1:リンクをたどる(ハイパーメディア駆動)

const pet = await fetch(petUrl);
const ownerUrl = pet._links.owner.href;
const owner = await fetch(ownerUrl);

オプション2:URLを構築する(従来型)

const pet = await fetch(`https://petstoreapi.com/v1/pets/${petId}`);
const owner = await fetch(`https://petstoreapi.com/v1/users/${pet.ownerId}`);

どちらのアプローチも機能します。リンクは利便性のために提供されており、強制ではありません。

Apidogを使ったハイパーメディアAPIのテスト

Apidogは、ハイパーメディアリンクをテストし、リンクの正確性を検証するのに役立ちます。

リンクの存在をテストする

レスポンスに期待されるリンクが含まれていることを確認する:

// Apidog test script
pm.test("レスポンスにページネーションリンクが含まれていることを確認", () => {
  const links = pm.response.json().links;
  pm.expect(links).to.have.property('self');
  pm.expect(links).to.have.property('next');
});

リンクの有効性をテストする

リンクをたどり、機能することを確認する:

// Apidog test script
const nextUrl = pm.response.json().links.next;

pm.sendRequest(nextUrl, (err, response) => {
  pm.test("次のリンクが200を返すか確認", () => {
    pm.expect(response.code).to.equal(200);
  });
});

リンク形式をテストする

リンクが期待される形式に従っていることを確認する:

pm.test("リンクが絶対URLであることを確認", () => {
  const links = pm.response.json().links;
  Object.values(links).forEach(link => {
    pm.expect(link).to.match(/^https:\/\//);
  });
});

HATEOASを使うべき時

価値をもたらすときにハイパーメディアリンクを使用しましょう。そうでないときはスキップしましょう。

ハイパーメディアリンクを使用すべきケース:

1. ページネーション - クライアントがページネーションURLを構築すべきではない

2. 関連リソース - 便利なナビゲーション

3. 状態依存型アクション - リソースの状態に基づいて利用可能なアクションを表示する

4. 複雑なワークフロー - クライアントを多段階プロセスに誘導する

HATEOASをスキップすべきケース:

1. シンプルなCRUD API - クライアントがURLを簡単に構築できる

2. 内部API - チーム間でURL変更を調整できる

3. パフォーマンスが重要なAPI - 余分なリンクがレスポンスサイズを増やす

4. モバイルAPI - 帯域幅が重要であり、リンクはオーバーヘッドを増やす

結論

HATEOASは理論的には優雅ですが、実用上は複雑です。ほとんどのAPIは完全なHATEOASをスキップし、価値をもたらす場所で選択的にハイパーメディアリンクを使用します。

Modern PetstoreAPIは、ページネーションリンク、関連リソースリンク、アクションリンクといった実用的なハイパーメディアを、クライアントに完全にハイパーメディア駆動であることを強制することなく示しています。

Apidogを使用して、ハイパーメディアリンクをテストし、リンクの正確性を検証し、APIが有用なナビゲーションを提供していることを確認してください。

主なポイント:

実用的なハイパーメディア実装を見るために、Modern PetstoreAPIドキュメントを探索してください。

ボタン

FAQ

REST APIにHATEOASは必須ですか?

ロイ・フィールディング(RESTの考案者)によると、はい。しかし実際には、いいえ。ほとんどの「REST」APIはHATEOASをスキップしており、技術的には「HTTP API」または「RESTライクなAPI」です。

HATEOASは何の略ですか?

Hypermedia as the Engine of Application State(アプリケーション状態のエンジンとしてのハイパーメディア)です。これは、クライアントがURLをハードコードするのではなく、ハイパーメディアリンクを通じてAPIの機能を発見することを意味します。

主要なAPIはHATEOASを使用していますか?

いいえ。GitHub、Stripe、Twilio、およびほとんどの主要なAPIは完全なHATEOASを使用していません。一部のハイパーメディアリンク(ページネーション、関連リソース)を含めることはありますが、クライアントがハイパーメディア駆動であることを要求しません。

HATEOASとハイパーメディアリンクの違いは何ですか?

HATEOASは、クライアントが完全にハイパーメディア駆動であることを要求する制約です。ハイパーメディアリンクは、レスポンス内の単なるリンクです。HATEOASを強制せずにリンクを含めることができます。

自分のAPIにHATEOASを実装すべきですか?

おそらく完全なHATEOASは実装すべきではありません。ページネーションや関連リソースのために選択的なハイパーメディアリンクを使用しましょう。特定の理由がない限り、クライアントにハイパーメディア駆動であることを強制しないでください。

HATEOAS APIはどのようにテストしますか?

Apidogを使用して、リンクの存在を確認し、リンクをたどり、リンクの正確性を検証します。リンクが期待されるレスポンスを返すことをテストしてください。

HALフォーマットとは何ですか?

HAL(Hypertext Application Language)は、ハイパーメディアリンクの標準フォーマットです。_links_embeddedフィールドを使用します。Modern PetstoreAPIはHALにインスパイアされたリンク形式を使用しています。

クライアントはハイパーメディアリンクを無視できますか?

はい。APIがリンクを提供しているが、クライアントがそれらを使用することを要求しない場合、クライアントはURLを直接構築できます。これはほとんどのAPIが採用している実用的なアプローチです。

ApidogでAPIデザイン中心のアプローチを取る

APIの開発と利用をよりシンプルなことにする方法を発見できる