24 ポイント 投稿者 GN⁺ 2025-07-10 | 1件のコメント | WhatsAppで共有
  • Roy FieldingのRESTの原典論文では、HTTPメソッドやCRUD中心のAPI利用を明確に規定しておらず、RESTは本来**ハイパーメディアベース(HATEOAS)**のシステム設計を強調している
  • 多くの人がRESTful APIと呼んでいるものは、重要なREST制約条件(特にハイパーメディアの利用)を実装していない
  • リソースは単純なデータ構造やエンティティに限定されず、URIで識別可能なあらゆる概念を含む
  • Fieldingの6つのルールによれば、ハイパーメディア中心の探索、プロトコル非依存性、メディアタイプ重視などが中核である
  • 現実的には、OpenAPIなどのドキュメント化ツールの利便性のために、ほとんどのAPIは真のRESTfulというよりRPCスタイルに近く設計される傾向が強い

ほとんどのRESTful APIが真にRESTfulではない理由

  • Roy Fieldingの**代表的論文(2000年)**は、REST(Representational State Transfer)をネットワークベースのソフトウェア設計における理想的なスタイルとして提示し、Webの成功を支える原理として説明している
  • この論文では、HTTPメソッドの使用やCRUD中心設計を必須とは規定しておらず、RESTを志向する際には**ハイパーメディア(HATEOAS)**に基づく状態遷移、統一インターフェース、リソース中心の相互作用が核心であることを強調している

ハイパーメディア(HATEOAS)とRESTに関する誤解

  • Fieldingは、ハイパーメディアのないAPIはRESTfulではないと明確に指摘している
    • 「エンジンがハイパーテキストによって駆動されていなければRESTfulではない」
  • HATEOASとは、クライアントがサーバー応答に埋め込まれたリンクをたどって動的に振る舞いを探索する方式である
  • 単にHTTP/CRUDインターフェースだけを使うことは、RESTの本質とは異なる

RESTのよくある誤解

  • RESTはCRUDだという認識(実際にはもっと広い概念)
  • リソースはエンティティ(サーバーのデータ構造)だという誤解
  • RESTful APIでは動詞(Verb)を使ってはいけないという主張
  • これらは設計上の判断にすぎず、RESTの本質とは直接関係がない

ハイパーメディア駆動(HATEOAS)の実際の意味

  • HATEOASの目的は、クライアントとサーバーの結合度を最小化することにある
  • サーバーのURI構造が変更された際、クライアント再配布の負担を減らし、拡張性と進化可能性を高める
  • クライアントは、ドキュメントや事前知識なしに応答内のハイパーリンクをたどって動作を探索する
    {  
      "orderId": 123,  
      "\_links": {  
        "self": { "href": "/orders/123" },  
        "cancel": { "href": "/orders/123/cancel", "method": "POST" }  
      }  
    }  
    
  • このように応答にアクション(リンク)が含まれていることで、真のRESTfulに近づく

RESTにおけるリソースとは何か?

  • リソースとはURIで識別可能なあらゆるものである
    • 文書、画像、物理的オブジェクト、サービス、抽象的概念などを含む
  • サーバーに実体としての「リソース」が存在するのではなく、URIでアクセス可能な抽象的マッピング構造があるにすぎない
  • RFC 3986でもリソースの範囲は限定されていない
    • 電子文書、画像、情報源、サービス、さらには人・法人・書籍なども含められる

Fieldingが定義したRESTful APIの6つのルール

  • 1. 単一プロトコルに依存しないこと
    • URIベースの識別は、あらゆるプロトコルで活用可能であるべき
  • 2. プロトコル(例: HTTP)の標準を恣意的に変更しないこと
    • 標準の不足を補うことは可能だが、独自ルールの追加や変更はしてはならない
  • 3. URI構造ではなくメディアタイプ(フォーマット)の定義に注力すること
    • データ形式とリンク定義に集中し、パス仕様やドキュメント化に無駄な労力を費やさない
  • 4. 固定されたURI命名や階層構造をハードコーディングしないこと
    • クライアントがサーバーの名前空間構造を推測・固定しないよう、リンクベースの探索を促す
  • 5. リソースタイプ(内部分類)を露出しないこと
    • 内部オブジェクト型はクライアントにとって無意味であり、標準メディアタイプとリンクだけを公開する
  • 6. ブックマーク(初期URI)だけが必要で、残りは応答のリンクで探索すること
    • クライアントは標準メディアタイプだけを知っていればよく、状態遷移は常にサーバー応答内のハイパーリンクに基づいて行われるべきである

ルールの解釈と実際の適用

  • プロトコル、URI、型への結合を最小化してこそ、真にRESTfulに近づく
  • APIはデータとリンクの形式(メディアタイプ)に集中すべきであり、URI構造や命名規則などをクライアントが事前に知る必要はない
  • たとえば/users/123/activateのようなパスを仕様化するのではなく、応答内の"activate"リンクで動作を案内すべきである

実際にRESTful APIがまれな理由

  • OpenAPI、Swaggerなどのツールの利便性が開発現場では優先される
    • 自動ドキュメント生成、コード生成、バリデーションなど、実務上の利点を提供する
  • クライアントとサーバーを同じチームが開発するSPA環境では、URI結合の問題に対する必要性がそれほど高くなく、HATEOASの利点が目立ちにくい
  • REST原則の初期学習コストや、動的リンク解析の複雑さなど、実用上の障壁が大きい

結論

  • Fieldingのルールによれば、真のRESTful APIにはハイパーメディア(HATEOAS)に基づく動的探索が不可欠である
  • RESTとは単にHTTP上でCRUDを実装することではなく、Webの原理と同様に疎結合・進化可能性・動的な状態遷移に焦点を当てたアーキテクチャである
  • 現実には、実用性とチームの状況に合った設計の方が重要である場合もある
    • 外部開発者向けのパブリックAPIであればHATEOASの採用が推奨されるが、内部専用APIならシンプルなRPCスタイルも実用的である
  • APIは学びやすく、誤用しにくいように設計することが重要であり、必ずしもRESTfulである必要はない

1件のコメント

 
GN⁺ 2025-07-10
Hacker Newsの意見
  • 私はここで見られる行き過ぎた原理主義には共感するし、Fieldingの論文も興味深く読んだが、これはもう終わった戦争だと感じた。REST APIという言葉を聞いた瞬間、次のことはほぼ確信できる

    • APIはJSONを返す
    • CRUD操作がPOST/GET/PUT/DELETEにマッピングされる
    • チームは適切なHTTPステータスコードについて延々と議論し、一部のコードは仕様と異なる使われ方をする
    • 複雑なフィルタ対応のためにlisting endpointがPOSTに変わる可能性もある Agile、CI、DevOpsのように、最初の定義にこだわるか、あるいはすでに社会的な意味が変わったのだから、単に通用している意味で用語を使うことになる
    • Fieldingが勝った理由は、まさに彼の論理が矛盾していて、その大半が間違っていたからだと思う。21世紀の「worse is better」パラダイムだ。RPCシステムは使い勝手が悪く成功しなかった。その例としてSun RPC、RMI、DCOM、CORBA、XML-RPC、SOAP、Protocol Buffersなどがある。人々はRESTはRPCではないと言うが、実際にはJavaScriptで
    const getItem = async (itemId) => { ... }
    

    のような関数を作り、この関数は

    GET /item/{item_id}
    

    を呼び出す。バックエンドには

    Item getItem(String itemId) { ... }
    

    のような関数があり、アノテーションでURLマッピングを説明する。結局これはRPCだ。ただし、複雑で直感的でないシステムの代わりに、もう少し手作業的で開発者が制御できる形で残っているだけだ。問題の80%の原因は、人々がISO 8601の日付フォーマットを使わないことだ

    • なぜ誰かがこれを「戦い」だと捉えて気にするのか、あまり理解できない。RESTの概念は有用だが、HATEOASの部分は実用性がほとんどなく、問題ばかり作る。Richardson maturity modelを見ると、RESTの頂点にはHATEOASのような要素が含まれている。RESTからHATEOASが抜けたらRESTとは言えないという論理も理解できないし、そんなに大きな差別化でもない。HATEOASが実質的にほとんど無意味なら、この原理主義的な分類に執着する意味はないように思う。Richardson maturity model

    • 「チームがステータスコードについて過剰に議論し、HTTP specと違う使い方をすることが多い」という部分では、401 Unauthorizedは認証されていない場合、403 Forbiddenは権限がない場合に使うべきだと強調したい

    • 私は人々に、Paperで定義されたRESTの意味を本当に使うつもりなのか尋ねるようにしている。たいていは意味のない用語の乱用を容認しない立場だ。結局「なるほど、単なるWeb APIのことね」と言って流す。重要なのは、APIごとにどこが変なのかを把握しなければならないという違いだ

    • 私にとって本当に重要なニュアンスは、「ハイパーメディアリンク」がさまざまなlink type(HTTPヘッダーや返却結果に含まれる)によって「汎用的」であるかのように見えても、実際には今日のRESTも同じように動くという点だ。たとえば、もし設計が悪くて"activate"ではなく"enable"であるべきだったなら、結局 /api/v1/account/ID/activate から /api/v2/account/ID/enable に変えなければならない。つまり、APIではすべてのアクションの意味をどこかにハードコードしなければならない(そしてアイコンやアクション説明の翻訳など追加メタデータも不足している)。この方式の「汎用性」は実際には錯覚だ

  • 13年前に初めてHTTP APIを開発することになったとき、本当のRESTとは何かを把握するためにFieldingの論文を最初から最後まで読み、RESTful Web Services Cookbookも読んだ。そしてDjangoの慣習を避けながらREST APIを作った。これは一種の「カーゴカルト」的アプローチで、本当のRESTが私たちのサービスにどんな利点をもたらすのかはよく分かっていなかった。その後さらに数年、さまざまなHTTP APIを作るうちに、結局実務ではREST原論がもたらす利点はないと感じた。「セルフディスカバリー」と「ジェネリッククライアントとの互換性」というビジョンはほとんど実現不可能で、Fieldingの論文自体もこのあたりを完全には導いてくれない。本当にself-discoverableなAPIを作るには、「エンドポイントディスカバリープロトコル」「オペレーション記述」「ヘルプメッセージ」など具体的なルールが必要だ。そして結局、そのルールを理解する専用クライアントを作らなければならず、そうなると汎用クライアントの利点は消える。つまり現実には、サービス専用のAPI/JSコード/CLIなど、結局はサーバーごとのカスタムコードを作るしかなかった。そして良いUXはRESTの理想と衝突する。フロントにアプリ特化コードを作ってこそ、本当に良いUXが得られる。UI要素を標準化することも一応できるが、実際にはJavaScriptのような言語で柔軟にUIを作るほうがずっと有用だ

    • self-discoverable APIという概念の限界には共感する。本当のRESTクライアントは実質的に実装不可能だ。すべてのURLの動作を知っていなければならず、新しく追加される動作があれば(例: /cansofspam/123/frobnicate)、クライアントはそれを明確に処理できない。結局クライアントの更新が必要になるか、無視するか、せいぜい非常に単純なボタン(例: Frobnicate)を追加できるだけだ。だから実際には、完全な意味でのRESTサーバーやクライアントは存在しない。現実的には、クライアントがディスカバリーなしで期待するAPIだけをサポートする形で運用される

    • APIにはさまざまな側面があるので、説明するのが難しい。API利用者は、平均応答遅延、再試行可能なエラーコード、アクションの原子性/冪等性なども知る必要がある。HATEOASだけではこうしたことは分からない。完全なRESTを実装する必要はなく、基本的にRESTの利点は、名詞/動詞をHTTPメソッドとURLにマッピングする統一言語があるという点にすぎない。それでも細かな設計や検討事項は非常に多い。たとえばHTTP spec上は許可されていても実際のLBでは使えないことや、500エラーをリトライする基準やバックオフロジックなどを気にしなければならない

    • ブラウザこそが「ジェネリックコード」であり、私たちが毎日使っている最高のUXを提供している。RESTの概念には、サーバーがクライアントにコードを渡すことも含まれる(セキュリティ上の問題はあるが、ブラウザと標準がそのあたりもかなり解決している)。Fielding論文内の関連部分リンク

    • 実のところ、RESTの定義も弱めたバージョンではあまり得るものがない。「リソース削除にはDELETEを必ず使うべきだ」というのはそれほど重要ではない。単にPOSTを使って、誰が困るのか?

    • 私は「self-discoverable」が目標だと考えたこともないし、達成可能なことだとも思わない。単純なクライアント設計では、そもそも期待が大きすぎる。特に、TFAでも「discoverable」という言葉自体が出てこない

  • この種のAPIデザインが本当に役立つのは、ユーザーと、それを代わりに探索するagent(例: ブラウザ)がAPIを探索し、各レスポンス内のメディアタイプやリンク情報に応じて相互作用できる場合だ。ほとんどのWeb APIはこうしたuse-caseではなく、特定のUI/UXを目指すWebアプリ向けに設計されている。これは意図的に選ばれた方向性だ。アプリ開発者は、アプリの目標のためにデータ表現やUIフローなどを完全に制御したい。REST API設計は、利用者がAPIリソースの使い方をより主体的にコントロールすべき場合に必要になる。例として

    • 誰でもアクセスできる政府情報ポータル(法令、天気、不動産記録など)
    • 各種書式の提出が必要な政府ポータル
    • WikipediaやOpenStreetMapのようなopen dataプロジェクト こうした分野こそREST APIデザインを導入すべき領域だ。結局、RESTの定義を厳密に問う人たちは学術的な背景を持つことが多く、一方で広い意味で使う人たちはアプリ体験を重視する開発者だと言える。答えは単純で、本物のRESTでないならRESTと呼ばなければよい
    • 実際、HTML文書がまさにその例だ。文書の中には別の文書へのリンクがあり、利用者はリンクに書かれたテキストに従ってどこへでも移動できる。もし利用者向けならUIと呼び、アプリケーション向けならAPIと呼ぶ。HATEOASが的外れに感じられる理由は、APIを直接利用者向けにしようとしているように見えるからだ。しかし私たちはすでにUIという形でそれを享受している

    • 純粋なRESTの概念は非常に学術的だ。オープンデータ/ビッグデータのプロジェクトで実際の性能やアーキテクチャを実現するには、REST達成の有無よりも現実的なアプローチのほうが重要だ。学者でさえ最終的には成果物を作らなければならないので、完全なRESTだけに固執はしない

    • こういう種類のAPI設計は、Webページだけでなく他のクライアントを作るときにも有用だ。GETでリソースを取得してフィールド/パスから値を抽出し、新しいURIを作って操作するなど、似たパターンでさまざまなアプリ/CLI/UIを構築できる。non-SPAならHTMLでそのまま実装することも可能で、結局は利用者(あるいはuser-agent)が返却表現内部の情報をdereferenceしているのだ

    • AIがAPIを利用する時代になれば、このuse-caseがより重要になるのか気になる。APIのdiscoverabilityはWebアプリ開発者よりもAIにずっと有利だ。MCP(没入型制御プロトコル)を見ると、tool discoverabilityがいかに強力か分かる。HATEOASはこうしたbare API利用にも大きな潜在的利点を与えるかもしれない

    • 米国気象局のRESTfulサービスAPIドキュメントへのリンクのように、公開情報APIがうまく設計されていると本当に快適だ

  • 「本当にハイパーメディアベースのクライアントを作る初期の認知負荷が非常に大きく感じられ、単にURIテンプレート(/users/{id}/orders など)をハードコードするほうが楽に感じた」という話に関しては、実際そのほうが簡単だと経験的に実感する。純正RESTの原則は大半の状況でコストに対する効用が低い。まるで電子レンジで、1つのボタンでメニュー/動作方式/時間を全部操作する仕組みが、単に標準的なボタンの機能を覚えて使うよりずっと面倒なのと同じだ。私が実際に使っている2ボタンのエンジンコードリーダーも驚くほど操作しづらい。今なおFieldingの論文を必ず読めと言う文化は、かなり深刻な論点だと思う。良いアイデアなら、さまざまな方法で大衆的な視点から分かりやすく説明できるはずだ。たとえば、物理を理解するのにNewtonのPrincipiaを必ず読めという人はいない

  • RESTful/HATEOASパターンを導入して本当に価値が出るには、それを理解するクライアントが必要だ。htmx: hypermedia clients intercoolerjs: hatoeas-is-for-humans

  • UIデザイナーは画面の細かな見た目を制御したがる。リソースに対して可能なあるアクションは大きなボタンにし、別のものはメニューに隠したり、UIにまったく表示しなかったりすることもある。アクションが状態ごとに動的にAPIレスポンスに基づいてレンダリングされるなら、すべてのアクションが同じように見えてしまう。だからRESTful APIは一般的なWebフロントエンドUIの実装には不向きだと思う

    • この主張には多くの誤りがある

      1. UXデザイナーは製品開発サイクル全体に関与するが、常に無条件でコントロール権を持っているわけではない。UI内での特定アクションの配置は、アクションの「state」とは別問題だ。つまり、状態による制約があればUXもその制約に従わなければならない
      2. アーキテクチャ的にstateチェックをラップすれば、「if (state === something)」より「if (resource.links['action'] !== null)」のほうがずっと良い場合もある。ほとんどのstate変化はサーバーでのvalidationが必要で、それをサーバー側だけに実装すればフロントの複雑さも下げられる。私はHATEOASアプリをかなり長く開発しており、HAL4Jも管理している。複雑さはあるが、UIデザイン自体が参入障壁ではない
    • 私の経験では、「RESTful API」の開発がUIと直接結びつくことはあまりなかった。本当にUIだけが必要なら、そもそもAPI自体が不要だ。単にサーバー主導方式(昔のDWRなど)でもよい

  • HATEOASは現実ではほとんど使われていないように見えるのに、なぜいまだにこうして議論されるのか、正直よく分からない。本当にこれを使っているところがあるのか、そして実際にどんな「自動探索クライアント」がサーバー情報を事前に知らなくてよいのか気になる

    • ACME(Let’s Encryptのプロトコル)がHATEOASベースであることを思い出してほしい。これは事実上、ほとんどのHTTPSサービスで使われている。HTTP自体も、本来きちんと使えばHATEOASプロトコルだ。「auto-discovery」とは、link typeや「next」などでリソースを探索できることだ。ただしクライアントは「next」の意味を事前に知っている必要はある。LLMもこうした自動探索は得意だ

    • エンタープライズ級のビデオ監視システムでHATEOASを活用したことがある。バージョン/権限の問題をAPIレベルで見事に解決した。複数のRFCも併用した。ただし最大の問題は、人々がモデルを壊す方向で「便利さ」を追求し、その結果かえって複雑性を生んでしまうことだった。また、JSONは本質的にハイパーテキスト形式ではないので、application/jsonにHATEOASを無理やり埋め込もうとすると不自然だった

    • HATEOASを使ってコメントを入力しているし、今まさに返信もしている。それを処理する「魔法の自動探索クライアント」は、まさに「Webブラウザ」だ

    • htmxが最も現実的な試みかもしれない

    • ODataのような標準もほとんど使われておらず、しかもそれほどpopularでもない。HATEOASは人気も標準性も不足しているので、なおさら広がらないようだ

  • この議論でいつも見落とされがちなのは、バックエンドAPI利用者のタイプだ。RESTとHATEOASは、通常バックエンドを直接所有していないサードパーティが利用するときに意味が大きい。たとえば従来のHTMLページの最終的な利用者はブラウザ利用者だ。最近のMCPも、多様なJSON RPC APIに対して「ディスカバリーと解釈」が必要なケースがあるから登場した。一方で、フロントとバックエンドが1対1で密結合している場合、RESTの利点はコストに見合わないことが多い。よりジェネリックな形でドキュメントや仕様を書く必要があり、実務ではseparation of concernsを無視して生産性を高めるツール(trPCなど)のほうが役立つことも多い。プロトタイプ段階ではend-to-end統合が速い

  • HATEOASとschema reference(XSD、JSON Schemaなど)によって動的探索クライアントが可能だという主張については、現実にはJSON schemaの「additionalProperties」のような機能が、かえって問題の原点を繰り返してしまうと思う。「out of band」方式でドキュメントを渡すほうが堅牢だろう。だとしたら、もし「_links」に単にSwagger文書へのリンクを1つだけ置いて、そのself path情報をクライアントに処理させるならどうだろうか? そうなると、なぜ「_links」が存在する必要があるのか? そんな複雑なJSON文書を扱えるクライアントがあるなら、むしろSwaggerテンプレートなどのほうが情報密度も動的性もずっと高い。CRUDリンクだけではAPI全体を十分に説明できず、JSON schemaですべてをカバーするのも不可能だ

  • 単にHTTP APIと呼べばみんな幸せになる。REST自体、そもそもAPI向けに設計されたものではなかった。最初からRESTは、人が受け取る情報システムのためのものであって、プログラムのためのものではなかった