我正在开发一个主要用作 API 的应用程序(除了一些次要视图,例如会话/注册,这将是“标准”)。我喜欢最终确定的方法Railscast #350:API 版本控制 http://railscasts.com/episodes/350-rest-api-versioning,于是也跟着做了。我的路线如下:
namespace :api, :defaults => {:format => 'json'} do
scope :module => :v1, :constraints => ApiConstraints.new(:version => 1, :default => false) do
resources :posts, :only => [:create, :show, :destroy, :index]
end
scope :module => :v2, :constraints => ApiConstraints.new(:version => 2, :default => true) do
resources :posts, :only => [:create, :show, :destroy, :index]
end
end
在每个路由中,我的 Constraint 是一个新的 ApiConstraints 对象,它位于我的./lib
文件夹。该类看起来像这样:
class ApiConstraints
def initialize(options)
@version = options[:version]
@default = options[:default]
end
def matches?(req)
@default || req.headers['Accept'].include?("application/vnd.MYAPP.v#{@version}")
end
end
现在,当手动测试时,一切都按预期进行。在我的 API 中,每个版本可能有 5 到 10 个控制器,并且不想测试 API 约束是否适用于每个单独的控制器,因为这没有意义。我正在寻找一个测试我的 API 约束的规范文件,但我不确定将该规范放在哪里。
我试过添加一个spec/routing/api_spec.rb
文件来测试事物,但它无法正常工作,因为它抱怨未提供某些内容,如下所示:
it "should route an unversioned request to the latest version" do
expect(:get => "/api/posts", :format => "json").to route_to(:controller => "api/v1/posts")
end
即使控制器正确匹配,上面的代码也会抛出错误。它失败并出现以下错误:
The recognized options <{"format"=>"json", "action"=>"index", "controller"=>"api/v1/posts"}>
did not match <{"controller"=>"api/v1/posts"}>,
difference: <{"format"=>"json", "action"=>"index"}>.
请注意,控制器已正确确定,但由于我不想在此测试中测试格式和操作,因此会出错。我希望有 3 个“API 规范”:
- 它应该将未版本控制的请求路由到最新版本
- 如果未指定,则默认为 JSON 格式
- 它应该在请求时返回指定的 API 版本
有人有为此类路线编写规范的经验吗?我不想为 API 内的每个控制器添加规范,因为它们不负责此功能。