实践中的REST Web服务版本控制 [英] REST web service versioning in practice

查看:78
本文介绍了实践中的REST Web服务版本控制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个新的Web服务,我已经阅读了一些来自APIgee的电子书,其中建议对Web服务进行版本控制。我知道在URL和标题中保留版本信息之间存在一些争执。根据我的阅读和理解,我想在标题中使用版本。

I am creating a new web service and I have read some of the ebooks from APIgee where versioning the web service is a recommended. I understand there is some "battle" between keeping versioning info in the URL vs. the header. From what I have read and understand I want to use versioning in the header.

我的问题是;这在实践中看起来如何?我正在使用Spring MVC 3.2。你是否只是在相同的控制器中创建一个响应不同版本的方法?

My question is; how does this looks like in practice? I am using Spring MVC 3.2. Do you just create a methods like this in the same controller which responds to different versions?

版本1:

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

版本2:

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

或者这是错的?或者更常见的是创建包含不同版本控制器的不同包?或者还有其他方法吗?

Or is this wrong? Or is it more usual to create different packages that holds different versions of the controller? Or are there other ways?

推荐答案

这里的问题不是关于版本信息所在的位置(URI与标题)以及更多关于如何组织不同版本的代码。

The issue here is less about where the version information lives (URI vs header) and more about how you organize code for different versions.

我怀疑有一种标准方法。它只取决于版本的不同程度。

I doubt there's a single standard approach. It just depends on how different the versions are.

简单的格式更改。假设唯一的区别是您从XML迁移到了V2中的V1到JSON。在这种情况下,您可以使用完全相同的代码,但只需将应用程序配置为全局输出JSON。不需要不同的包或控制器。 (例如,您可以使用JAXB注释来驱动XML和Jackson生成的JSON输出。)

Simple format change. Suppose for example that the only difference was that you moved from XML in V1 to JSON in V2. In that case you could use exactly the same code, but just configure the app to output JSON globally instead. No need for different packages or controllers. (For example you can use JAXB annotations to drive both XML and Jackson-generated JSON output.)

适度的架构更改。说V2引入少量破坏架构的变化。在这种情况下,在它上面创建新包可能没有意义。您可能只需要在控制器中使用简单的条件逻辑来处理/提供版本的正确表示。

Modest schema changes. Say that V2 introduces a small number of breaking schema changes. In this case it probably wouldn't make sense to create new packages over it. You might just have simple conditional logic in your controller to process/serve the right representation for the version.

主要架构更改。如果您的架构变化很深且范围很广,您可能需要的不仅仅是单独的控制器。您甚至可能需要不同的域模型(实体/服务)。在这种情况下,为控制器提供一组并行的包,一直到实体,repos甚至数据库表都可能是有意义的。

Major schema changes. If your schema changes are deep and far-ranging, you might need more than separate controllers. You might even need a different domain model (entities/services). In this case it may well make sense to have a parallel set of packages for controllers all the way down to the entities, repos and maybe even database tables.

方法1。将这些想法应用于 @RequestMapping 示例,你可以做什么你说那里,但如果版本之间的响应完全相同,那么他们应该只委托一个共享方法:

Approach 1. Applying these ideas your @RequestMapping examples, you could do what you say there, but if the response is exactly the same between versions, then they should just delegate to a single shared method:

@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);
}

这样的东西会起作用。如果版本之间的订单不同,那么您可以在方法中实现差异。

Something like that would work. If the orders are different between versions then you can implement the differences right in the method.

方法2。您可能尝试的另一件事 - 并且我没有尝试过这个 - 每个资源类型(例如,订单,产品,客户等)都有自己的基本控制器和HTTP方法的方法级注释(只需 value 方法已定义,但生成)。然后使用扩展基础的特定于版本的扩展,其中扩展控制器具有 @RequestMapping(value =/ orders,produce =application / vnd.example-v1)在班级。然后仅覆盖版本和基线之间的增量。 我不确定这是否可行但是如果是这样的话,组织控制器将是一种非常干净的方式。这就是我的意思:

Approach 2. Another thing you might try--and I haven't myself tried this--is each resource type (e.g., orders, products, customers, etc.) having its own base controller with method-level annotations for the HTTP method (just value and method defined, but not produces). Then use version-specific extensions that extend the base, where the extension controllers have the @RequestMapping(value = "/orders", produces = "application/vnd.example-v1") at the class level. Then override only deltas between the version and the baseline. I'm not sure whether this will work but if so it would be a pretty clean way to organize controllers. Here's what I mean:

// 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);
    }
}

这篇关于实践中的REST Web服务版本控制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆