我正在创建一个新的网络服务,我已经阅读了一些来自 APIgee 的电子书,其中建议对网络服务进行版本控制。我知道在 URL 和 header 中保留版本控制信息之间存在一些“斗争”。根据我所阅读和理解的内容,我想在 header 中使用版本控制。
我的问题是;这在实践中看起来如何?我正在使用 Spring MVC 3.2。您是否只是在响应不同版本的同一 Controller 中创建这样的方法?
版本 1:
@RequestMapping(method = RequestMethod.GET, produces = "application/vnd.example-v1+json")
版本 2:
@RequestMapping(method = RequestMethod.GET, produces = "application/vnd.example-v2+json")
或者这是错误的?或者更常见的是创建包含不同版本 Controller 的不同包?还是有其他方法?
最佳答案
这里的问题不在于版本信息所在的位置(URI 与 header ),而在于如何为不同版本组织代码。
我怀疑是否存在单一的标准方法。这仅取决于版本的不同程度。
简单的格式更改。例如,假设唯一的区别是您从 V1 中的 XML 移动到 V2 中的 JSON。在那种情况下,您可以使用完全相同的代码,但只需将应用配置为全局输出 JSON。不需要不同的包或 Controller 。 (例如,您可以使用 JAXB 注释来驱动 XML 和 Jackson 生成的 JSON 输出。)
适度的架构更改。假设 V2 引入了少量破坏性架构更改。在这种情况下,在它上面创建新包可能没有意义。您的 Controller 中可能只有简单的条件逻辑来处理/提供版本的正确表示。
主要架构更改。如果您的架构更改很深且范围很广,您可能需要的不仅仅是单独的 Controller 。您甚至可能需要不同的域模型(实体/服务)。在这种情况下,为 Controller 一直到实体、存储库甚至数据库表提供一组并行的包可能很有意义。
方法 1. 将这些想法应用到您的 @RequestMapping 示例中,您可以按照您在那里所说的去做,但是如果版本之间的响应完全相同,那么它们应该只需委托(delegate)给一个共享方法:
@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. 您可能会尝试的另一件事——我自己还没有尝试过——是每种资源类型(例如,订单、产品、客户等)都有自己的基础具有 HTTP 方法的方法级注释的 Controller (仅定义了 value 和 method,但没有定义 produces)。然后使用扩展基础的特定于版本的扩展,其中扩展 Controller 在类级别具有 @RequestMapping(value = "/orders", produces = "application/vnd.example-v1") .然后仅覆盖版本和基线之间的增量。 我不确定这是否可行,但如果可行,这将是组织 Controller 的一种非常干净的方式。这就是我的意思:
// 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);
}
}
关于java - REST Web 服务版本控制实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18936264/
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
当我在Rails控制台中按向上或向左箭头时,出现此错误:irb(main):001:0>/Users/me/.rvm/gems/ruby-2.0.0-p247/gems/rb-readline-0.4.2/lib/rbreadline.rb:4269:in`blockin_rl_dispatch_subseq':invalidbytesequenceinUTF-8(ArgumentError)我使用rvm来管理我的ruby安装。我正在使用=>ruby-2.0.0-p247[x86_64]我使用bundle来管理我的gem,并且我有rb-readline(0.4.2)(人们推荐的最少
我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.
最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru
我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这
在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo