[解決済み] SpringでREST APIのバージョン管理を行うには?
質問
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
,
RequestMappingHandlerMapping
と
RequestMappingInfo
を含む)、これは私が好きではない、なぜなら私がspringの新しいバージョンにアップグレードすることを決定するたびに余分な作業を意味するからです。
私はどんな考えにも感謝します...そして特に、よりシンプルでメンテナンスしやすい方法でこれを行うためのどんな提案にも感謝します。
編集
バウンティの追加 懸賞金を得るには、このロジックをコントローラ自体に持たせることを提案せずに、上記の質問に答えてください。Springはすでにどのコントローラのメソッドを呼び出すかを選択するロジックをたくさん持っており、私はそれにおんぶにだっこしたいのです。
編集2
オリジナルのPOC(一部改良あり)をgithubで共有しました。 https://github.com/augusto/restVersioning
どのように解決するのですか?
後方互換性のある変更を行うことでバージョン管理を回避できるかどうかに関係なく (企業のガイドラインに縛られていたり、API クライアントがバグだらけの方法で実装されていて、たとえ壊れていなくても壊れてしまう場合は、常に可能とは限りません)、抽象化された要件は興味深いものです。
メソッド本体で評価を行わずに、リクエストからヘッダー値の任意の評価を行うカスタム リクエスト マッピングを行うにはどうしたらよいでしょうか。
で説明されているように
このSOの回答
を持つことができます。
@RequestMapping
を使用し、実行時に発生する実際のルーティングを区別するために別のアノテーションを使用することができます。そうするためには、以下のようになります。
-
新しいアノテーションを作成します。
VersionRange
. -
を実装します。
RequestCondition<VersionRange>
. ベストマッチアルゴリズムのようなものを使用することになるので、他のVersionRange
の値でアノテーションされたメソッドが、 現在のリクエストによりよくマッチするかどうかをチェックする必要があります。 -
を実装します。
VersionRangeRequestMappingHandlerMapping
をアノテーションとリクエスト条件に基づいて実装します(ポスト RequestMappingのカスタムプロパティを実装する方法 ). -
を評価するようにspringを設定します。
VersionRangeRequestMappingHandlerMapping
を評価するように設定します。RequestMappingHandlerMapping
(を使用する前に(例えば、その順序を 0 に設定することによって)。
これは、Springコンポーネントの面倒な置き換えを必要としませんが、Springの設定と拡張のメカニズムを使用するので、Springのバージョンを更新しても(新しいバージョンがこれらのメカニズムをサポートしている限り)動作するはずです。
関連
-
プロジェクトの依存関係を解決できなかった 解決
-
javaコンパイル時のエラー:不正な文字 '\ufeff' に対する解決策です。
-
IDEA パッケージステートメントの欠落
-
java -serverコマンドで「Error: no `server' JVM at ... jvm.dll」を解決する方法です。
-
[解決済み] cURLでJSONデータをPOSTするにはどうすればよいですか?
-
[解決済み] Mavenを使用して、依存関係を持つ実行可能なJARを作成するにはどうすればよいですか?
-
[解決済み] Spring Bootアプリケーションにポートを設定する方法
-
[解決済み] RESTアプリケーションはステートレスであることが前提である場合、セッションはどのように管理するのですか?
-
[解決済み】REST APIでのPUTメソッドとPATCHメソッドの使い分け 実生活でのシナリオ
-
[解決済み] Spring Boot RESTサービスの例外処理
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
jd-gui Java Exceptionが発生しました。
-
SpringBootApplication を型解決できない。
-
Javaクラスローダーにソースコードから潜り込む
-
javaの模造品QQ WeChatのチャットルーム
-
eclipse の実行時に java 仮想マシンが見つからなかった
-
Spring boot runs with Error creating bean with name 'entityManagerFactory' defined in class path resource
-
サーブレットクラスのインスタンス化エラーの解決法
-
スレッド "main" で例外発生 java.lang.ArrayIndexOutOfBoundsException: 0 at One1.main(One1.java:3)
-
SocketTimeoutExceptionです。読み込みがタイムアウトしました
-
起動時にEclipseエラーが発生しました。起動中に内部エラーが発生しました。java.lang.NullPoin: "Javaツーリングの初期化 "中に内部エラーが発生しました。