私は、HTTPベースのインターフェースを何でもREST APIと呼ぶ人の数に不満を感じています。今日の例はSocialSite REST APIです。あれはRPCです。明らかにRPCです。結合度が非常に高いため、X指定にするべきです。
ハイパーテキストが制約であるという概念をRESTアーキテクチャスタイルで明確にするために、何がなされる必要があるのでしょうか?言い換えれば、アプリケーションの状態(そしてAPI)のエンジンがハイパーテキストによって駆動されていない場合、RESTfulではなく、REST APIになることはできません。終わりです。修正が必要な壊れたマニュアルはどこかにありますか?
–ロイ・フィールディング(RESTという用語の考案者)
RESTは、コンピュータプログラミングの歴史の中で最も広く誤用されている専門用語と言えるでしょう。
他にこれに近いものはないと思います。
今日、誰かがRESTという用語を使う場合、ほとんどの場合、HTTPを使用するJSONベースのAPIについて議論しています。
RESTについて言及している求人広告や、RESTガイドラインについて議論している企業を見ても、ハイパーテキストやハイパーメディアについて言及することはめったにありません。代わりに、JSON、GraphQL(!)などを言及します。
頑固な少人数だけが不平を言います。「しかし、これらのJSON APIはRESTfulではありません!」と。
この記事では、RESTの簡潔で不完全で、ほとんど間違っている歴史と、その意味がRESTがもともと対比されていたもの、つまりRPCとほぼ完全に逆の意味になるようになった経緯を説明したいと思います。
REpresentational State Transferの略であるRESTという用語は、フィールディング博士論文の第5章から生まれました。フィールディングは、(当時新しい)ワールドワイドウェブのネットワークアーキテクチャを説明し、他の可能なネットワークアーキテクチャ、特にRPCスタイルのネットワークアーキテクチャと対比していました。
彼の執筆当時(1999〜2000年)にはJSON APIは存在しなかったことを理解することが重要です。彼は当時存在していたウェブ、つまりHTMLがHTTP経由で交換され、人々が「ウェブを閲覧」していたウェブについて説明していました。JSONはまだ作成されておらず、JSONの広範な採用には10年かかりました。
RESTはネットワークアーキテクチャを記述したものであり、APIに対する制約という観点から定義されました。RESTful APIと見なされるためには、これらの制約を満たす必要がありました。その言語は学術的なものであり、このトピックに関する混乱に貢献してきましたが、ほとんどの開発者が理解できる程度には十分明確です。
RESTには多くの制約と概念がありますが、他の可能なネットワークアーキテクチャと対比した場合、RESTの定義上最も重要な特徴であると私が考える重要なアイデアが1つあります。
これは統一インターフェース制約として知られており、その概念の中で、特にハイパーメディア・アズ・ザ・エンジン・オブ・アプリケーション・ステート(HATEOAS)、あるいはフィールディングが好んで呼ぶように、ハイパーメディア制約という考え方が重要です。
この統一インターフェース制約を理解するために、銀行口座に関する情報を返す2つのHTTPレスポンスを検討してみましょう。1つはHTML(ハイパーテキスト)、もう1つはJSONです。
HTTP/1.1 200 OK
<html>
<body>
<div>Account number: 12345</div>
<div>Balance: $100.00 USD</div>
<div>Links:
<a href="/accounts/12345/deposits">deposits</a>
<a href="/accounts/12345/withdrawals">withdrawals</a>
<a href="/accounts/12345/transfers">transfers</a>
<a href="/accounts/12345/close-requests">close-requests</a>
</div>
<body>
</html>
HTTP/1.1 200 OK
{
"account_number": 12345,
"balance": {
"currency": "usd",
"value": 100.00
},
"status": "good"
}
これらの2つのレスポンスの決定的な違い、そしてなぜHTMLレスポンスはRESTfulだがJSONレスポンスはそうではないのか、それはこの点です。
HTMLレスポンスは完全に自己記述的です。
このレスポンスを受信する適切なハイパーメディアクライアントは、銀行口座とは何か、残高とは何かなどを知りません。単にハイパーメディア、HTMLをレンダリングする方法を知っているだけです。
クライアントは、このデータに関連付けられたAPIエンドポイントについて、HTML自体で見つけることができるURLとハイパーメディアコントロール(リンクとフォーム)以外には何も知りません。リソースの状態が変化して、そのリソースで利用可能なアクションが変わる場合(たとえば、口座がオーバードラフトになった場合)、HTMLレスポンスは変更されて利用可能な新しいアクションセットが表示されます。
クライアントはこの新しいHTMLをレンダリングしますが、「オーバードラフト」の意味や、実際には銀行口座の意味さえも知りません。
このようにして、ハイパーテキストはアプリケーションの状態のエンジンとなります。HTMLレスポンスは、システムとの対話を続けるために必要なすべてのAPI情報を、自身の中に直接「含めて」います。
さて、これを2番目のJSONレスポンスと比較してみましょう。
この場合、メッセージは自己記述的ではありません。むしろ、クライアントは適切なユーザーインターフェースを表示するために`status`フィールドを解釈する方法を知っている必要があります。さらに、クライアントは、「帯域外」情報、つまりレスポンス以外の情報源(Swagger APIドキュメントなど)から取得されるURL、パラメータなどの情報に基づいて、アカウントで利用可能なアクションを認識する必要があります。
JSONレスポンスは自己記述的ではなく、ハイパーメディア内にリソースの状態をエンコードしません。したがって、RESTの統一インターフェース制約に違反するため、RESTfulではありません。
REST APIはハイパーメディア駆動型でなければなりませんで、フィールディングは次のように述べています。
REST APIは、最初のURI(ブックマーク)と、目的のオーディエンスに適した標準化されたメディアタイプのセット(つまり、APIを使用する可能性のあるクライアントによって理解されると予想されるもの)以外の事前知識なしで開始する必要があります。その時点以降、すべてのアプリケーション状態遷移は、受信した表現に存在するか、またはユーザーによるこれらの表現の操作によって暗黙的に示されている、サーバーが提供する選択肢のクライアントによる選択によって駆動されなければなりません。
したがって、RESTfulシステムでは、単一のURLを介してシステムに入り、その時点以降、システム内で実行されるすべてのナビゲーションとアクションは、完全に自己記述的なハイパーメディア、たとえばHTMLのリンクとフォームを介して提供される必要があります。適切なRESTfulシステムでは、エントリポイントを超えて、APIクライアントはAPIに関する追加情報(APIに関する追加情報)を必要としません。
これは、RESTfulシステムの驚くべき柔軟性の源泉です。すべてのレスポンスは自己記述的で、現在利用可能なすべての操作をエンコードしているため、たとえばAPIのバージョン管理について心配する必要はありません!実際、ドキュメントを作成する必要さえありません!
状況が変われば、ハイパーメディアレスポンスが変わり、それだけです。
分散システムを構築するための非常に柔軟で革新的な概念です。
今日、ほとんどのウェブ開発者と企業は、2番目の例をRESTful APIと呼びます。
彼らは、おそらく最初のレスポンスをAPIレスポンスと見なすことさえしません。ただのHTMLです!
(かわいそうなHTML、全く尊敬されていない。)
APIは常にJSONか、もしあなたが凝っているなら、Protobufのようなものですよね?
違います。
皆さんは間違っていて、気分が悪いはずです。
最初のレスポンスはAPIレスポンスであり、実際にはRESTfulな方です!
2番目のレスポンスは、実際にはリモートプロシージャコール(RPC)スタイルのAPIです。クライアントとサーバーは、フィールディングが2008年に不満を述べたSocialSite APIのように結合されています。クライアントは、JSONレスポンス自体以外の他の情報源から取得する必要がある、操作しているリソースに関する追加の知識を持っている必要があります。
このAPIは、精神的にはRESTのほぼ正反対です。
このスタイルのAPIを「RESTレス」と呼びましょう。
では、どうすれば明らかにRESTfulではないAPIが業界の99.9%によってRESTfulと呼ばれている状況になるのでしょうか?
面白い話です。
ロイ・フィールディングは2000年に彼の論文を発表しました。
ほぼ同時期に、明示的にRPCに触発されたプロトコルであるXML-RPCがリリースされ、HTTPを使用してAPIを構築する方法として勢いを増し始めました。XML-RPCは、マイクロソフトのSOAPと呼ばれるより大きなプロジェクトの一部でした。XML-RPCは、主にエンタープライズの世界からの多くの静的型付けと初期のXML最大主義を組み込んだ、長いRPCスタイルのプロトコルの伝統から生まれました。
また、この時に登場したのがAJAX、つまり非同期JavaScriptとXMLです。ここでXMLに注目してください。皆さんがご存知のように、AJAXにより、ブラウザはバックグラウンドでサーバーにHTTPリクエストを発行し、JavaScriptで直接レスポンスを処理できるようになり、ウェブプログラミングの全く新しい世界が開かれました。
問題は、それらのリクエストをどのようにするかということです。明らかにXMLになるでしょう。名前の通りです。そして、この新しいSOAP/XML-RPC標準が出てきました。これが正しいことだったのでしょうか?
フィールディングが記述した異なる種類のアーキテクチャを持つウェブに気づいた人々が現れ、「Webサービス」と呼ばれるものへのアクセス方法として、SOAPではなくRESTを使用すべきかどうかを尋ね始めました。ウェブは非常に柔軟で急成長しており、ブラウザと人間にとって非常にうまく機能しているのと同じネットワークアーキテクチャであるRESTが、APIにもうまく機能する可能性がありました。
特にAPIの形式がXMLの場合、それはもっともらしく聞こえました。XMLはHTMLと非常によく似ていませんか?統一インターフェースを含むすべてのRESTful制約を満たすXML APIを想像できます。
そこで、人々はこれも探求し始めました。
これらすべてが起こっている間、別の重要なテクノロジーが誕生しつつありました。JSON
JSONは(文字通り)SOAP/RPC-XMLのJavaに対するJavaScriptでした。シンプルで、ダイナミックで、簡単です。JSONがほとんどのWeb APIの支配的な形式である現在では信じられませんが、JSONが普及するまでには時間がかかりました。2008年頃でも、API開発に関する議論は主にXMLに関するものであり、JSONではありませんでした。
2008年、Martin Fowler は、特定の API がどの程度 RESTful であるかを判断するためのモデルであるリチャードソン成熟度モデルを紹介する記事を発表しました。
このモデルは4つの「レベル」を提案しており、最初のレベルはPlain Old XML、つまりPOXの沼です。
そこから、API は以下の概念を採用するにつれて、REST API としてより「成熟した」ものとみなされるようになりました。
GET
、POST
、DELETE
などを適切に使用)レベル3では統一インターフェースが導入されるため、このレベルは最も成熟したレベルであり、「RESTの栄光」と見なされています。
RESTという用語にとって不運なことに、この時期に2つのことが起こりました。
SOAP/XML-RPCが非常に過剰設計されていたため、JSONは急速にWebサービス/APIの世界を席巻しました。JSONはシンプルで、「ただ動作した」ため、読みやすく理解しやすいものでした。
この変化により、Web開発の世界はJ2EEの考え方の束縛を完全に打ち破り、SOAP/XML-RPCをエンタープライズ専用の物にしました。
RESTアプローチはSOAP/XML-RPCほどXMLに縛られておらず、エンドポイントにそれほど多くの形式を課していなかったため、JSONが取って代わる自然な場所でした。そして、それは急速にそうしました。
この重要な変化の中で、ほとんどのJSON APIがRMMのレベル2で止まっていることがますます明らかになりました。
レスポンスにハイパーメディアコントロールを組み込むことでレベル3まで到達したAPIもありましたが、ほとんどすべてのAPIは依然としてドキュメントを公開する必要があり、「RESTの栄光」は達成されていませんでした。
レスポンス形式としてJSONが普及したことも、大きなヒントだったはずです。JSONは明らかにハイパーテキストではありません。上にハイパーメディアコントロールを課すことはできますが、自然ではありません。XMLは少なくともHTMLに似ていたので、ハイパーメディアを作成できる可能性がありました。
JSONは単なるデータでした。ハイパーメディアコントロールの追加はぎこちなく、標準化されておらず、統一インターフェースの制約で記述されている方法でめったに使用されませんでした。
これらの困難にもかかわらず、「REST」という用語は残りました。RESTはSOAPの反対であり、JSON APIはSOAPではなく、したがってJSON APIはRESTでした。
これが私たちがここに至った経緯の1文要約です。
JSON APIの世界では真にRESTfulなAPIが常に実現されていなかったにもかかわらず、作成されているRESTレスなAPIが「RESTful」かどうかをめぐって多くの論争がありました。URLレイアウト、特定のアクションに適したHTTP動詞、メディアタイプに関する激しい議論などです。
当時私は若く、全体が不透明で、清教徒的で、疎外感を感じさせるものだったので、REST全体の概念をほぼ諦めていました。それはインターネットで高圧的な人々が議論するものでした。
私がめったに言及されていないこと(または、言及されていても理解できなかったこと)は、統一インターフェースの概念とそれがRESTfulシステムにとっていかに重要であるかということです。
intercooler.jsを作成し、何人かの賢い人がそれがRESTfulであると私に言い始めたときに、再びその考えに興味を持つようになりました。
RESTful?それはJSON APIのことです。私のフロントエンドライブラリのハックがどのようにしてRESTfulになり得るのでしょうか?
そこで調べて、Fieldingの論文を新鮮な目で再読し、なんと、intercoolerはRESTfulであるだけでなく、私が扱っていたすべての「RESTful」JSON APIはまったくRESTfulではなかったのです!
そして、それ以来、私はインターネットを涙で濡らしてきました。
最終的に、ほとんどの人はJSON APIにハイパーメディアコントロールを追加することに疲れ、それを諦めました。これらのコントロールは特定の特殊な状況(例:ページング)ではうまく機能しましたが、RESTが一般的な人間中心のインターネットで見つけた広範で明らかなユーティリティは決して達成しませんでした。(その理由に関する私の仮説があります。)
物事はこの中間的なRESTレス状態に落ち着き、RESTはRMMのレベル1または2でのJSON APIとしての意味をゆっくりと固めていきました。しかし、レベル3とRESTの栄光に到達する可能性は常にありました。
そしてシングルページアプリケーション(SPA)が登場しました。
SPAが登場したとき、Web開発は元の基盤となるRESTfulアーキテクチャから完全に切り離されました。SPAアプリケーションの *全体のネットワークアーキテクチャ* がJSON RPCスタイルに移行しました。さらに、これらのアプリケーションの複雑さのために、開発者はフロントエンドとバックエンドに特化しました。
フロントエンド開発者は明らかにRESTfulなことを何もしていませんでした。彼らはJavaScriptを使ってDOMオブジェクトを作成し、必要に応じてAJAX APIを呼び出していました。これは、初期のWebのようなものではなく、むしろリッチクライアントオーサリングにずっと似ていました。
バックエンドエンジニアは、ある程度ネットワークアーキテクチャに関心があり、「REST」という用語を自分たちが行っていることを説明するために使い続けました。
RESTful APIのSwaggerドキュメントを公開したり、RESTful APIのAPI変更を不満に思ったりするなど、実際にRESTful APIを作成していれば発生しないことを行っていたにもかかわらずです。
最後に、2010年代後半、人々は耐え忍ぶのにうんざりしました。RESTレスな形であっても、RESTはますます複雑化するSPAアプリケーションのニーズに対応できませんでした。アプリケーションはますますリッチクライアントのようになり、リッチクライアントの問題にはリッチクライアントのソリューションが必要であり、劣化したハイパーメディアクライアントのソリューションではありません。
GraphQLがリリースされたときに、ダムは本当に壊れました。
GraphQLはRESTとはほど遠いものです。GraphQLを使用するAPIを操作する方法を理解するには、絶対に *ドキュメントが必要です* 。クライアントとサーバーは非常に緊密に結合されています。ネイティブのハイパーメディアコントロールはありません。スキーマを提供し、多くの点で、更新され、簡素化されたXML-RPCのバージョンのように感じられます。
そしてここで言いたいのは、それはOKということです!
多くの人がGraphQLを本当に気に入っており、リッチクライアントスタイルのアプリケーションを構築している場合、それは非常に理にかなっています。
この質問に対する簡潔な答えは、HATEOASがAPIのほとんどの最新のユースケースには適していないということです。そのため、約20年経っても、HATEOASは開発者の間で広く採用されていません。一方、GraphQLは現実の問題を解決するため、急速に普及しています。
したがって、GraphQLはRESTではなく、RESTであるとは主張しておらず、RESTになることを望んでいません。
しかし、今日現在、ほとんどの開発者や企業は、APIにGraphQL機能を熱心に追加しているにもかかわらず、「REST」という用語を自分たちが構築しているものを説明するために使い続けています。
残念ながら、voidfuncはおそらく正しいでしょう。
いくら看板を叩いても無駄です。その戦いはとっくに終わっています。RESTは、人々がHTTP+JSON RPCを呼ぶための一般的な用語です。
明らかにRESTではないJSON APIをRESTと呼び続けるでしょう。なぜなら、それが今や誰もがそう呼んでいるものだからです。
私がいくら熱心に看板を叩いても、50年後にはGlobal Omni Corp.は依然として、RESTful JSON APIのSwaggerドキュメントのv138に取り組むための求人を掲載しているでしょう。
それにもかかわらず、REST、特に統一インターフェースを、元の文脈でこれらの概念を聞いたことがなく、REST === JSON APIだと仮定している新世代のWeb開発者に説明する機会があります。
人々は何かが間違っていると感じています。そして、おそらくREST、本当の実際のREST、RESTレスではないRESTがその答えの一部になるかもしれません。
少なくとも、RESTの背後にある考え方は興味深く、一般的なソフトウェアエンジニアリングの知識として知っておく価値があります。
ここには、より大きなメタポイントもあります。比較的賢い人々のグループ(初期のWeb開発者)でさえ、インターネットの恩恵を受け、RESTという用語に対してかなり明確な(時折学術的な)仕様があったにもかかわらず、20年間にわたってその意味を元の意味と一致させることができませんでした。
私たちがこれほど明らかに間違えることができるなら、他に何が間違っているのでしょうか?