1. ホーム
  2. java

[解決済み] SpringでREST APIのバージョン管理を行うには?

2022-06-12 06:40:38

質問

Spring 3.2.xを使ってREST APIのバージョンを管理する方法を探しているのですが、メンテナンスが簡単なものが見当たりません。まず、私が抱えている問題を説明し、次に解決策を説明しますが、ここで車輪の再発明をしているのではないかと思っています。

私はAcceptヘッダに基づいてバージョンを管理したいのですが、例えばリクエストがAcceptヘッダを持つ場合 application/vnd.company.app-1.1+json がある場合、spring MVCがこのバージョンを処理するメソッドに転送するようにしたいのです。また、APIのすべてのメソッドが同じリリースで変更されるわけではないので、バージョン間で変更されていないハンドラに対して、各コントローラに移動して何かを変更することはしたくありません。また、Springがすでにどのメソッドを呼び出すかを発見しているので、コントローラ自身でどのバージョンを使用するかを見つけ出すロジックを持ちたくありません(サービスロケータを使用します)。

バージョン1.0から1.8までのAPIで、あるハンドラがバージョン1.0で導入され、v1.7で変更されたとすると、次のように処理したいと思います。コントローラの中に、ヘッダからバージョンを抽出するコードがあるとします。(以下はSpringでは無効です)

@RequestMapping(...)
@VersionRange(1.0,1.6)
@ResponseBody
public Object method1() {
   // so something
   return object;
}

@RequestMapping(...) //same Request mapping annotation
@VersionRange(1.7)
@ResponseBody
public Object method2() {
   // so something
   return object;
}

これは、springでは2つのメソッドが同じ RequestMapping のアノテーションがあり、Springでは読み込みに失敗します。考え方としては VersionRange アノテーションで、オープンまたはクローズドなバージョン範囲を定義できることです。最初の方法はバージョン1.0から1.6まで有効で、2番目の方法はバージョン1.7以降(最新のバージョン1.8を含む)に対して有効です。私は、誰かがバージョン 99.99 を渡すことを決定した場合、この方法が壊れることを知っていますが、それは私が我慢できることなのです。

さて、上記のことは Spring がどのように動作するかを真剣に作り直さない限り不可能なので、私はハンドラがリクエストにマッチする方法をいじろうと考えていました、特に、私自身の ProducesRequestCondition を書き、そこにバージョンの範囲を持たせようと考えています。例えば

コードです。

@RequestMapping(..., produces = "application/vnd.company.app-[1.0-1.6]+json)
@ResponseBody
public Object method1() {
   // so something
   return object;
}

@RequestMapping(..., produces = "application/vnd.company.app-[1.7-]+json)
@ResponseBody
public Object method2() {
   // so something
   return object;
}

この方法で、アノテーションのプロデュース部分でクローズドまたはオープンなバージョン範囲を定義することができます。現在、この解決策に取り組んでいますが、まだSpring MVCのコアクラス( RequestMappingInfoHandlerMapping , RequestMappingHandlerMappingRequestMappingInfo を含む)、これは私が好きではない、なぜなら私がspringの新しいバージョンにアップグレードすることを決定するたびに余分な作業を意味するからです。

私はどんな考えにも感謝します...そして特に、よりシンプルでメンテナンスしやすい方法でこれを行うためのどんな提案にも感謝します。


編集

バウンティの追加 懸賞金を得るには、このロジックをコントローラ自体に持たせることを提案せずに、上記の質問に答えてください。Springはすでにどのコントローラのメソッドを呼び出すかを選択するロジックをたくさん持っており、私はそれにおんぶにだっこしたいのです。


編集2

オリジナルのPOC(一部改良あり)をgithubで共有しました。 https://github.com/augusto/restVersioning

どのように解決するのですか?

後方互換性のある変更を行うことでバージョン管理を回避できるかどうかに関係なく (企業のガイドラインに縛られていたり、API クライアントがバグだらけの方法で実装されていて、たとえ壊れていなくても壊れてしまう場合は、常に可能とは限りません)、抽象化された要件は興味深いものです。

メソッド本体で評価を行わずに、リクエストからヘッダー値の任意の評価を行うカスタム リクエスト マッピングを行うにはどうしたらよいでしょうか。

で説明されているように このSOの回答 を持つことができます。 @RequestMapping を使用し、実行時に発生する実際のルーティングを区別するために別のアノテーションを使用することができます。そうするためには、以下のようになります。

  1. 新しいアノテーションを作成します。 VersionRange .
  2. を実装します。 RequestCondition<VersionRange> . ベストマッチアルゴリズムのようなものを使用することになるので、他の VersionRange の値でアノテーションされたメソッドが、 現在のリクエストによりよくマッチするかどうかをチェックする必要があります。
  3. を実装します。 VersionRangeRequestMappingHandlerMapping をアノテーションとリクエスト条件に基づいて実装します(ポスト RequestMappingのカスタムプロパティを実装する方法 ).
  4. を評価するようにspringを設定します。 VersionRangeRequestMappingHandlerMapping を評価するように設定します。 RequestMappingHandlerMapping (を使用する前に(例えば、その順序を 0 に設定することによって)。

これは、Springコンポーネントの面倒な置き換えを必要としませんが、Springの設定と拡張のメカニズムを使用するので、Springのバージョンを更新しても(新しいバージョンがこれらのメカニズムをサポートしている限り)動作するはずです。