web-dev-qa-db-ja.com

REST予測された変更を計画しているエンドポイントの推奨パターンは何ですか?

変更に対する先見性を備えた外部アプリケーション用のAPIを設計するのは簡単ではありませんが、少し前もって考えておくと、後で作業が楽になります。以前のバージョンのハンドラーをそのまま残して、下位互換性を維持しながら将来の変更をサポートするスキームを確立しようとしています。

この記事の主な関心事は、特定の製品/会社に対して定義されたすべてのエンドポイントについて従うべきパターンです。

基本スキーム

ベースURLテンプレートがhttps://rest.product.com/の場合、すべてのサービスは/apiおよび/authなどの他の非休憩ベースのエンドポイントとともに/docの下に存在するように考案しました。したがって、次のようにベースエンドポイントを設定できます。

https://rest.product.com/api/...
https://rest.product.com/auth/login
https://rest.product.com/auth/logout
https://rest.product.com/doc/...

サービスエンドポイント

次に、エンドポイント自体について説明します。 POSTGETDELETEに関する懸念は、この記事の主な目的ではなく、それらのアクション自体に対する懸念です。

エンドポイントは名前空間とアクションに分解できます。各アクションは、戻り値の型または必須パラメーターの根本的な変更をサポートする方法で表示される必要もあります。

登録ユーザーがメッセージを送信できる架空のチャットサービスを利用して、次のエンドポイントを設定できます。

https://rest.product.com/api/messages/list/{user}
https://rest.product.com/api/messages/send

次に、破壊される可能性のある将来のAPI変更のバージョンサポートを追加します。 /api/または/messages/の後にバージョン署名を追加できます。 sendエンドポイントを指定すると、v1に対して次のようになります。

https://rest.product.com/api/v1/messages/send
https://rest.product.com/api/messages/v1/send

だから私の最初の質問は、バージョン識別子の推奨場所は何ですか?

コントローラコードの管理

これで、以前のバージョンをサポートする必要があることを確認しました。これにより、時間の経過とともに廃止される可能性のある新しいバージョンそれぞれのコードを何らかの方法で処理する必要があります。エンドポイントをJavaで記述していると仮定すると、これをパッケージで管理できます。

package com.product.messages.v1;
public interface MessageController {
    void send();
    Message[] list();
}

これには、すべてのコードが名前空間を介して分離されているという利点があり、重大な変更があると、サービスエンドポイントの新しいコピーが作成されます。これのデメリットは、すべてのコードをコピーする必要があり、新しいバージョンと以前のバージョンに適用したいバグ修正を各コピーに適用/テストする必要があることです。

別のアプローチは、各エンドポイントのハンドラーを作成することです。

package com.product.messages;
public class MessageServiceImpl {
    public void send(String version) {
        getMessageSender(version).send();
    }
    // Assume we have a List of senders in order of newest to oldest.
    private MessageSender getMessageSender(String version) {
        for (MessageSender s : senders) {
            if (s.supportsVersion(version)) {
                return s;
            }
        }
    }
}

これにより、バージョン管理が各エンドポイント自体に分離され、ほとんどの場合一度だけ適用するだけでバグ修正のバックポート互換性が得られますが、これをサポートするには、個々のエンドポイントに対してかなり多くの作業を行う必要があることを意味します。

そこで、2つ目の質問があります。「以前のバージョンをサポートするためのRESTサービスコードを設計する最良の方法は何ですか?」

25
Brett Ryan

そこで、2つ目の質問があります。「以前のバージョンをサポートするためのRESTサービスコードを設計する最良の方法は何ですか?」

非常に注意深く設計されており、直交APIはおそらく下位互換性のない方法で変更する必要がないため、本当に最善の方法は将来のバージョンを持たないことです。

もちろん、おそらく最初の試みは実際には得られないでしょう。そう:

  • 計画しているように(そしてバージョン管理されているAPIであり、その中の個々のメソッドではなく)、APIにバージョンを付け、それについて多くのノイズを作ります。 APIが変更される可能性があること、およびアプリケーションが最新バージョンを使用しているかどうかを確認する必要があることをパートナーが知っていることを確認してください。また、新しいものが利用可能になったときにアップグレードするようユーザーにアドバイスします。 2つの古いバージョンをサポートするのは難しいですが、5つをサポートすることはできません。
  • すべての「リリース」でAPIバージョンを更新するという衝動に抵抗します。新しい機能は通常、既存のクライアントを壊すことなく現在のバージョンに組み込むことができます。それらは新機能です。あなたが望む最後のことは、とにかくほとんど後方互換性があるので、クライアントがignoreバージョン番号を使うことです。 APIのバージョンを更新するのは、既存のAPIを壊さずに前進できない場合のみにしてください。
  • 新しいバージョンを作成するときが来たら、最初のクライアントは前のバージョンの下位互換性のある実装でなければなりません。 「メンテナンスAPI」自体は、現在のAPIに実装する必要があります。この方法では、いくつかの完全な実装を維持するためのフックではありません。現在のバージョンのみ、および古いバージョンのいくつかの「シェル」。後方互換性のあるクライアントに対して廃止予定のAPIの回帰テストを実行することは、新しいAPIと互換性レイヤーの両方をテストする良い方法です。

最初のURI設計オプションは、API全体をバージョン管理するという考えをよりよく表現しています。 2番目は、メッセージ自体のバージョン管理と解釈できます。したがって、これはIMOの方が優れています。

rest.product.com/api/v1/messages/send

クライアントライブラリの場合、2つの完全な実装を別々のJavaパッケージで使用する方が、クリーンで使いやすく、保守も簡単だと思います。

とはいえ、APIを進化させるには、バージョン管理よりも優れた方法があります。私はあなたがそれに備える必要があることに同意しますが、私はバージョン管理を最後の手段として、慎重かつ慎重に使用することを考えています。クライアントがアップグレードするのは比較的大きな労力です。しばらく前に、私はこれらの考えのいくつかをブログ投稿に入れました:

http://theamiableapi.com/2011/10/18/api-design-best-practice-plan-for-evolution/

REST APIのバージョン管理については特に、Mark Nottinghamによるこの投稿を参考にしてください。

http://www.mnot.net/blog/2011/10/25/web_api_versioning_smackdown

3
Ferenc Mihaly

APIバージョン管理を処理する別のアプローチは、HTTPヘッダーでバージョンを使用することです。お気に入り

POST /messages/list/{user} HTTP/1.1
Host: http://rest.service.com
Content-Type: application/json
API-Version: 1.0      <----- like here
Cache-Control: no-cache

ヘッダーを解析して、バックエンドで適切に処理できます。

このアプローチでは、クライアントはURLを変更する必要はなく、ヘッダーを変更するだけです。また、これによりRESTエンドポイントが常にクリーンになります。

クライアントのいずれかがバージョンヘッダーを送信しなかった場合は、400-Bad requestを送信するか、backward-compatible APIのバージョンで処理できます。

3
sincerekamal