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>
?
无论如何,研究很有趣,我希望它对你有所帮助!
小智 37
要添加的几件事:
你的重定向匹配对某些路由不起作用 - *api
param是贪婪的并且会吞没一切,例如/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, ¤t_api_routes
namespace :v2, ¤t_api_routes
namespace :v1, ¤t_api_routes
match ":api/*path", :to => redirect("/api/v2/%{path}")
end
Run Code Online (Sandbox Code Playgroud)
这具有版本化和通用命名路由的额外好处.另外一个注意事项 - 使用时的约定:module
是使用下划线表示法,例如:api/v1
not'Api :: V1'.有一点后者没有用,但我相信它已在Rails 3.1中修复.
此外,当您发布API的v3时,路由将更新如下:
current_api_routes = lambda do
resources :users
end
namespace :api do
scope :module => :v3, ¤t_api_routes
namespace :v3, ¤t_api_routes
namespace :v2, ¤t_api_routes
namespace :v1, ¤t_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, ¤t_api_routes
namespace :v3, ¤t_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
如果可能的话,我建议重新考虑您的网址,以便版本不在网址中,但是会被放入接受标头中.这个堆栈溢出答案很好地解决了:
此链接显示了如何使用rails路由执行此操作:
http://freelancing-gods.com/posts/versioning_your_ap_is
我不是路由版权的忠实粉丝.我们构建了VersionCake以支持更简单的API版本控制.
通过在我们各自的视图(jbuilder,RABL等)的文件名中包含API版本号,我们保持版本控制不引人注意并允许容易降级以支持向后兼容性(例如,如果视图的v5不存在,我们渲染视图的v4).
如果没有明确请求版本,我不确定为什么要重定向到特定版本.您似乎只想定义在未明确请求版本的情况下提供的默认版本.我同意David Bock的说法,保持URL结构的版本是一种更清晰的方式来支持版本控制.
无耻插件:Versionist支持这些用例(以及更多).
https://github.com/bploetz/versionist