9

私は新しい Web サービスを作成しており、Web サービスのバージョン管理が推奨されている APIgee の電子ブックをいくつか読みました。URL とヘッダーにバージョン管理情報を保持することの間には、いくつかの「戦い」があることを理解しています。私が読んで理解したことから、ヘッダーでバージョン管理を使用したいと考えています。

私の質問は; これは実際にはどのように見えますか?Spring MVC 3.2 を使用しています。異なるバージョンに応答する同じコントローラーでこのようなメソッドを作成するだけですか?

バージョン 1:

@RequestMapping(method = RequestMethod.GET, produces = "application/vnd.example-v1+json")

バージョン 2:

@RequestMapping(method = RequestMethod.GET, produces = "application/vnd.example-v2+json")

それともこれは間違っていますか?それとも、異なるバージョンのコントローラーを保持する異なるパッケージを作成する方が一般的ですか? それとも他の方法がありますか?

4

1 に答える 1

19

ここでの問題は、バージョン情報が存在する場所 (URI とヘッダー) ではなく、異なるバージョンのコードをどのように編成するかです。

単一の標準的なアプローチがあるとは思えません。それは、バージョンの違いに依存します。

シンプルなフォーマット変更。たとえば、V1 の XML から V2 の JSON に移行したことが唯一の違いであるとします。その場合、まったく同じコードを使用できますが、代わりに JSON をグローバルに出力するようにアプリを構成するだけです。別のパッケージやコントローラーは必要ありません。(たとえば、JAXB アノテーションを使用して、XML と Jackson で生成された JSON 出力の両方を駆動できます。)

適度なスキーマ変更。V2 では、少数の重大なスキーマ変更が導入されているとします。この場合、その上に新しいパッケージを作成することはおそらく意味がありません。バージョンの正しい表現を処理/提供するために、コントローラーに単純な条件付きロジックがあるだけかもしれません。

主要なスキーマの変更。スキーマの変更が深く広範囲に及ぶ場合は、別のコントローラー以上のものが必要になる場合があります。別のドメイン モデル (エンティティ/サービス) が必要になる場合もあります。この場合、エンティティ、リポジトリ、場合によってはデータベース テーブルに至るまで、コントローラー用の並列パッケージ セットを用意することは理にかなっています。

アイデアの適用

アプローチ 1.これらのアイデアを@RequestMapping例に適用すると、そこで言うことを実行できますが、応答がバージョン間でまったく同じである場合は、単一の共有メソッドに委任する必要があります。

@RequestMapping(
    value = "/orders/{id}",
    method = RequestMethod.GET,
    produces = "application/vnd.example-v1")
@ResponseBody
public Order getOrderV1(@PathVariable("id") Long id) {
    return getOrder(id);
}

@RequestMapping(
    value = "/orders/{id}",
    method = RequestMethod.GET,
    produces = "application/vnd.example-v2")
@ResponseBody
public Order getOrderV2(@PathVariable("id") Long id) {
    return getOrder(id);
}

private Order getOrder(Long id) {
    return orderRepo.findOne(id);
}

そのようなものはうまくいくでしょう。バージョン間で順序が異なる場合は、メソッドで違いを実装できます。

アプローチ 2.もう 1 つ試してみることができますが、私自身は試していませんが、各リソース タイプ (注文、製品、顧客など) が、HTTP メソッドのメソッド レベルのアノテーションを備えた独自のベース コントローラーを持つことです。 (ちょうど定義されていますが、そうではありませんvalue) 。次に、ベースを拡張するバージョン固有の拡張機能を使用します。拡張コントローラーには、クラス レベルの があります。次に、バージョンとベースラインの間の差分のみをオーバーライドします。これが機能するかどうかはわかりませんが、機能する場合は、コントローラーを整理するためのかなりクリーンな方法になります。これが私が意味することです:methodproduces@RequestMapping(value = "/orders", produces = "application/vnd.example-v1")

// The baseline
public abstract class BaseOrderController {

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    @ResponseBody
    public Order getOrder(@PathVariable("id") Long id) { ... }
}    

// V1 controller
@RequestMapping(value = "/orders", produces = "application/vnd.example-v1")
public class OrderControllerV1 extends BaseOrderController {

    ... no difference from baseline, so nothing to implement ...
}

// V2 controller
@RequestMapping(value = "/orders", produces = "application/vnd.example-v2")
public class OrderControllerV2 extends BaseOrderController {

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    @ResponseBody
    @Override
    public Order getOrder(@PathVariable("id") Long id) {
        return orderRepoV2.findOne(id);
    }
}
于 2013-09-21T19:21:36.327 に答える