Rails路由的API版本控制

mal*_*tor 140 versioning routes ruby-on-rails ruby-on-rails-3

我正试图像Stripe那样对我的API进行版本测试.下面给出了最新的API版本是2.

/api/users 返回301到 /api/v2/users

/api/v1/users 在版本1返回200个用户索引

/api/v3/users 返回301到 /api/v2/users

/api/asdf/users 返回301到 /api/v2/users

因此,除非指定的版本存在,否则基本上任何未指定版本的内容都会链接到最新版本,然后重定向到它.

这是我到目前为止:

scope 'api', :format => :json do
  scope 'v:api_version', :api_version => /[12]/ do
    resources :users
  end

  match '/*path', :to => redirect { |params| "/api/v2/#{params[:path]}" }
end
Run Code Online (Sandbox Code Playgroud)

Rya*_*igg 275

这个答案的原始形式有很大的不同,可以在这里找到.只是证明有一种方法可以给猫皮肤.

我更新了答案,因为使用命名空间并使用301重定向 - 而不是默认值302.感谢pixeltrix和Bo Jeanes对这些事情的提示.


你可能想戴一个非常强大的头盔,因为这会让你大吃一惊.

Rails 3路由API是超级恶意的.要根据您的要求编写API的路由,您只需要:

namespace :api do
  namespace :v1 do
    resources :users
  end

  namespace :v2 do
    resources :users
  end
  match 'v:api/*path', :to => redirect("/api/v2/%{path}")
  match '*path', :to => redirect("/api/v2/%{path}")
end
Run Code Online (Sandbox Code Playgroud)

如果在这之后你的思想仍然完整,那么让我解释一下.

首先,namespace当你想要一堆作用于特定路径的路由和类似命名的模块时,我们称之为超级便利.在这种情况下,我们希望块内的所有路由namespace都限定在Api模块内的控制器,并且对此路由内的路径的所有请求都将以前缀为前缀api.请求如/api/v2/users,你知道吗?

在命名空间内,我们定义了两个名称空间(哇!).这次我们定义了"v1"命名空间,因此这里控制器的所有路由都在V1模块内的Api模块内:Api::V1.通过resources :users在此路线内定义,控制器将位于Api::V1::UsersController.这是版本1,你可以通过提出这样的请求到达那里/api/v1/users.

第2版只是一个很小的有点不同.而不是控制器服务它Api::V1::UsersController,它现在在Api::V2::UsersController.您可以通过生成类似的请求到达那里/api/v2/users.

接下来,使用a match.这将匹配所有类似的API路由/api/v3/users.

这是我必须要查找的部分.该:to =>选项允许您指定特定请求应该重定向到其他地方 - 我知道的很多 - 但我不知道如何让它重定向到其他地方并传入原始请求的一部分.

为此,我们调用该redirect方法并向其传递一个带有特殊插值%{path}参数的字符串.当一个请求进入匹配此final的请求时match,它会将path参数插入到%{path}字符串内部的位置,并将用户重定向到他们需要去的位置.

最后,我们使用另一个match路由前缀所有剩余路径/api并将其重定向到/api/v2/%{path}.这意味着请求/api/users会去/api/v2/users.

我无法弄清楚如何/api/asdf/users匹配,因为你如何确定这应该是一个请求/api/<resource>/<identifier>还是/api/<version>/<resource>

无论如何,研究很有趣,我希望它对你有所帮助!

  • 亲爱的Ryan Bigg.你太聪明了. (23认同)
  • 一个不仅仅是衡量Ruby Hero的声誉. (17认同)
  • 如果路径不正确,它是否会创建无限重定向?例如,请求/ api/v3/path_that_dont_match_the_routes将创建无限重定向,对吧? (3认同)
  • 值得注意的是,在路由文件301中已经成为默认重定向并且有充分理由.从指南:`请注意,此重定向是301"永久移动"重定向.请记住,某些Web浏览器或代理服务器会缓存此类重定向,从而使旧页面无法访问 (2认同)

小智 37

要添加的几件事:

你的重定向匹配对某些路由不起作用 - *apiparam是贪婪的并且会吞没一切,例如/api/asdf/users/1将重定向到/api/v2/1.你最好使用常规的param :api.不可否认,它不会匹配案例,/api/asdf/asdf/users/1但如果您在api中嵌套了资源,这是一个更好的解决方案.

瑞恩为什么不喜欢namespace?:-),例如:

current_api_routes = lambda do
  resources :users
end

namespace :api do
  scope :module => :v2, &current_api_routes
  namespace :v2, &current_api_routes
  namespace :v1, &current_api_routes
  match ":api/*path", :to => redirect("/api/v2/%{path}")
end
Run Code Online (Sandbox Code Playgroud)

这具有版本化和通用命名路由的额外好处.另外一个注意事项 - 使用时的约定:module是使用下划线表示法,例如:api/v1not'Api :: V1'.有一点后者没有用,但我相信它已在Rails 3.1中修复.

此外,当您发布API的v3时,路由将更新如下:

current_api_routes = lambda do
  resources :users
end

namespace :api do
  scope :module => :v3, &current_api_routes
  namespace :v3, &current_api_routes
  namespace :v2, &current_api_routes
  namespace :v1, &current_api_routes
  match ":api/*path", :to => redirect("/api/v3/%{path}")
end
Run Code Online (Sandbox Code Playgroud)

当然,您的API可能在版本之间有不同的路由,在这种情况下您可以执行此操作:

current_api_routes = lambda do
  # Define latest API
end

namespace :api do
  scope :module => :v3, &current_api_routes
  namespace :v3, &current_api_routes

  namespace :v2 do
    # Define API v2 routes
  end

  namespace :v1 do
    # Define API v1 routes
  end

  match ":api/*path", :to => redirect("/api/v3/%{path}")
end
Run Code Online (Sandbox Code Playgroud)


Dav*_*ock 13

如果可能的话,我建议重新考虑您的网址,以便版本不在网址中,但是会被放入接受标头中.这个堆栈溢出答案很好地解决了:

API版本控制的最佳实践?

此链接显示了如何使用rails路由执行此操作:

http://freelancing-gods.com/posts/versioning_your_ap_is


aan*_*tix 9

我不是路由版权的忠实粉丝.我们构建了VersionCake以支持更简单的API版本控制.

通过在我们各自的视图(jbuilder,RABL等)的文件名中包含API版本号,我们保持版本控制不引人注意并允许容易降级以支持向后兼容性(例如,如果视图的v5不存在,我们渲染视图的v4).


Bri*_*etz 8

如果没有明确请求版本,我不确定为什么要重定向到特定版本.您似乎只想定义在未明确请求版本的情况下提供的默认版本.我同意David Bock的说法,保持URL结构的版本是一种更清晰的方式来支持版本控制.

无耻插件:Versionist支持这些用例(以及更多).

https://github.com/bploetz/versionist