HN 日本語サマリー

← 一覧へ戻る
Web開発

APIがRESTfulであるとはどういうことか

What it means for an API to be RESTful (en.andros.dev)

13 pointsby ibobev6 コメント

要約

RESTful APIは、単にJSONを返すHTTP APIではなく、Roy Fieldingが定義したアーキテクチャスタイルであるRESTの制約(クライアント・サーバー、ステートレス、キャッシュ可能、レイヤードシステム、統一インターフェース、コードオンデマンド)に従うものです。特に、HATEOAS(Hypermedia as the Engine of Application State)により、APIは自己記述的でナビゲート可能になります。真にRESTfulなAPIは、リソース識別子、プロトコルの標準、メディアタイプ、そしてハイパーメディア(リンク)に焦点を当て、外部ドキュメントに依存せず、クライアントがAPIを探索できるようにします。

全文翻訳

申し訳ありませんが、RESTful APIとは何かをあなたは知りません。あなたは様々な種類のAPIを統合してきた経験豊富な開発者であり、複数の言語で何十ものAPIを本番環境で稼働させているかもしれません。しかし、それらのすべては、業界の良い慣行に従い、計り知れない量のドキュメントを読んだことを証明するだけであり、それは良いことです。しかし、それらのどれもRESTfulの知識を証明するものではありません。パニックになる必要はありません!あなただけではありません。私が知っているほとんどの開発者は、それを定義したり、実装したり、その強みを指摘したりすることはできません。だからこそ、この記事では、理解しやすい例でその美徳を説明します。そして、この記事を読み終えたら、APIの見方が変わるかもしれません。警告しておきます! API RESTfulは、REST API(Representational State Transfer)と同義語としてよく使われますが、ニュアンスが重要です。RESTはHTTPインターフェースではありません。それは、Roy Fieldingが博士論文(2000年)で定義したアーキテクチャスタイルであり、制約を課します。 クライアント・サーバーアーキテクチャ:クライアントとサーバーは分離されなければなりません。 ステートレス:サーバーへの各クライアントリクエストには、リクエストを理解し処理するために必要なすべての情報が含まれている必要があります。言い換えれば、サーバーはリクエスト間でクライアントの状態に関する情報を保持しません。 キャッシュ可能:レスポンスは、キャッシュ可能またはキャッシュ不可能として明示的にマークされなければなりません。 レイヤードシステム:アーキテクチャはレイヤーで構成でき、各レイヤーは特定の機能を持ち、互いに隔離されています。 統一インターフェース:クライアントとサーバー間の通信は、明確に定義されたパターンで予測可能でなければなりません。 コードオンデマンド(オプション):サーバーは、クライアントの機能を拡張するために、JavaScriptスクリプトなどの実行可能なコードをクライアントに送信できます。 つまり、RESTはリソースを提供するためのアーキテクチャ原則のセットであり、通常はHTTP経由で提供されます。それはWeb開発に深く根ざしており、非常に標準化されているため、それが見られないと奇妙に感じられます。 そして、不快な部分が来ます。厳密に言えば、RESTにはこの記事でこれから読むすべてが含まれています。ハイパーメディアは統一インターフェース制約の一部であり、「RESTful」は単なる形容詞、「RESTに準拠する」という意味です。人気のある使用法が「REST」を「JSONを返すHTTP API」という意味にまで低下させてしまい、Fielding自身が2008年に「REST APIはハイパーテキスト駆動でなければならない」という有名な記事を発表し、HTTPでドレスアップされたRPCをRESTと呼ぶことを嘆いています。 Richardson Maturity Modelは、その距離に数値を付けました:レベル0、単一のRPCスタイルのエンドポイント;レベル1、独自のURIを持つリソース;レベル2、HTTP動詞とステータスコードが正しく使用される;レベル3、ハイパーメディア。あなたが毎日利用する「REST」APIの大多数はレベル2にとどまっています。 この記事では、Fieldingが要求するレベル3、つまりレベル3を指すためにRESTfulを使用します。目標は、APIを予測可能で標準化された自己記述的なインターフェースに変えることです。基本URLだけで、クライアントは外部ドキュメントに頼ることなく、すべてのリソースを探索できるようになります。さらに、ルートを変更してもクライアントに影響を与えずに済む柔軟性や、複数の通信プロトコルを試すことができます。 しかし、まず知っておくべき概念があります:HATEOAS(Hypermedia as the Engine of Application State)。この概念は、RESTful APIがどのように自己記述的でナビゲート可能になるかを理解する上で基本的です。 HATEOAS(Hypermedia as the Engine of Application State) ハイパーメディアは、RESTfulの重要な特徴の1つです。これにより、クライアントはレスポンスで提供されるリンクを通じてリソースを動的に発見できます。これらは通常、_links親の下にあります。 { "id": 123, "name": "John Doe", "_links": { "self": { "href": "/users/123", "method": "GET" }, "update": { "href": "/users/123", "method": "PUT" }, "delete": { "href": "/users/123", "method": "DELETE" }, "friends": { "href": "/users/123/friends", "method": "GET" }, "posts": { "href": "/users/123/posts", "method": "GET" }, "search": { "href": "/search/?query={query}", "method": "GET", "templated": true } } } これにより、クライアントは、インターネットを閲覧するのと同様に、リンクを解析してフォローすることでAPIをナビゲートし、必要な情報に到達できます。さらに、相対ルート(href)を名前(オブジェクトキー)として使用してジャンプするため、バックエンドはアドレスを変更してもクライアントに影響を与えずに済みます。クライアントは固定されたルート構造に縛られないため、ノード間を移動できます。これは非常に強力です。 最後のリンクで使用されているtemplated: trueに注目してください。これは、hrefにURIテンプレート(RFC 6570に準拠)が含まれており、使用前に特定の値を埋める必要があることを示しています。これは、パラメータ化されたエンドポイントを発見するためのエレガントな方法です。たとえば、クライアントは{query}を「restful api」に置き換えて、関連コンテンツを検索できます。 続行する前に正直な注意:_links規約はHAL(Hypertext Application Language)に由来しますが、HALはmethodフィールドを定義していません。そのリンクはhref、templated、type、またはtitleのようなプロパティのみを考慮します。APIが自己記述的になるのに役立つため、また一般的な拡張機能であるため、メソッドを追加しました。フォーマットされたメソッドとフィールドを持つアクションが必要な場合は、Sirenを参照してください。純粋なHALを好む場合は、methodを省略し、プロトコルの規約(ルール2)を信頼してください。 すべてのリソースにハイパーメディアが必要なわけではありません。関連性のある、適切なコンテキストを持つものだけです。たとえば、ショッピングカートへのリンクをブログ記事に含めるのは意味がありませんが、記事に著者、コメント、または関連記事へのリンクを含めるのは興味深いでしょう。 HATEOASの重要性を理解したので、RESTful APIが従うべきルールを見てみましょう。 RESTful APIの6つのルール これらのルールは私が勝手に作ったものではありません。これらは、私が言及した記事でFieldingがリストした6つの条件であり、ここでは例とともに適応されています。 1. 単一のプロトコルに依存しない リソース識別子(URI)を使用してリソースを定義します。つまり、URL(http://example.com/api/users/123)を使用する代わりに、その場所を示しプロトコルを無視するURI(/users/123)を使用します。このようにして、WebSocket、MQTT、NNTP、RPCなどを使用できます。もちろんHTTPを使用できますが、それにのみ依存してはなりません。たとえば、APIがHTTP専用に設計されている場合、厳密にはRESTfulではありません。 2. プロトコルを変更しない 車輪の再発明をしないでください。プロトコルで創造的にならないでください。たとえば、HTTPを使用する場合、規約に従ってください:GETはリソースの取得、POSTは作成、PUTは置換、PATCHは部分更新、DELETEは削除に使用します。適切なHTTPレスポンスステータスを使用してください:200 OK、201 Created、204 No Content、400 Bad Request、404 Not Foundなど。MQTTを使用しますか?適切なコマンドとステータスを使用してください。 3. メディアタイプに焦点を当てる、URIではなく 各URIを外部で文書化する代わりに、APIが処理するメディアタイプを記述する必要があります。これは6つのルールのうち最も誤解されているルールであり、Fieldingによれば、記述的な努力のほとんどはここに行われるべきです。アイデアは、ルートのリスト(通常は「ドキュメント」と呼ぶもの)を公開するのではなく、メディアタイプ(たとえばapplication/vnd.myshop.product+json)を定義および文書化することです。つまり、各表現のフィールドの意味と、そのリンクの処理方法です。クライアントは、呼び出したURIではなく、受信したContent-Typeに基づいて何をするかを決定します。URIは交換可能な詳細になります。 たとえば、ユーザーに関する情報が少ないリソースは次のようになります。 { "id": 123, "name": "John Doe", "_links": { "self": "/users/123", "friends": "/users/123/friends", "lastInvoice": "/users/123/invoice/last" } } 一方、ユーザーに関する情報が多いリソースは次のようになります。 { "id": 123, "name": "John Doe", "_links": { "self": { "href": "/users/123", "method": "GET", "type": "application/json" }, "friends": { "href": "/users/123/friends", "method": "GET", "type": "text/csv" }, "lastInvoice": { "href": "/users/123/invoice/last", "method": "GET", "type": "appl" } } }