Railspath的API版本控制

我试图版本我的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

所以基本上没有指定最新版本的链接,除非指定的版本存在然后redirect到它。

这是我迄今为止:

 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 

这个答案的原始forms是非常不同的,可以在这里find 。 只是certificate有一个以上的方式来剥皮猫。

我已经更新了答案,因为使用了命名空间并使用了301redirect – 而不是默认的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 

如果在这之后你的头脑仍然完好无损,请让我解释一下。

首先,我们称之为namespace ,当你想把一堆路由作用到一个特定的path和命名模块时,它是非常方便的。 在这种情况下,我们希望namespace块内的所有路由都被限制在Api模块内的控制器上,并且对该路由内的path的所有请求都将以api为前缀。 请求/api/v2/users ,你知道吗?

在命名空间内部,我们定义了两个命名空间(哇!)。 这次我们定义了“v1”命名空间,所以这里的控制器的所有路由都将在Api模块中的V1模块中: Api::V1 。 通过定义resources :users这个路由中的resources :users ,控制器将位于Api::V1::UsersController 。 这是版本1,并通过提出请求/api/v1/users

版本2只是有点不同。 而不是控制器在Api::V1::UsersController它现在在Api::V2::UsersController 。 你通过提出/api/v2/users这样的请求来达到目的。

接下来,使用match 。 这将匹配所有API路由,如/api/v3/users

这是我必须查看的部分。 :to =>选项允许你指定一个特定的请求应该被redirect到别的地方 – 我知道的很多 – 但我不知道如何让它redirect到其他地方,并传入一个原始请求一起。

为此,我们调用redirect方法并将其传递给一个带有特殊插值的%{path}参数的string。 当匹配这个最终match的请求到达时,它会将path参数插入到string中%{path}的位置,并将用户redirect到他们需要去的地方。

最后,我们使用另一个match来路由前缀为/api所有剩余path,并将它们redirect到/api/v2/%{path} 。 这意味着像/api/users这样的请求会转到/api/v2/users

我无法弄清楚如何让/api/asdf/users匹配,因为你如何确定是否应该是/api/<resource>/<identifier>/api/<version>/<resource>

无论如何,这是很有趣的研究,我希望它可以帮助你!

添加几件事情:

你的redirect匹配不适用于某些路由 – *api参数是贪婪的,会吞噬一切,例如/api/asdf/users/1会redirect到/api/v2/1 。 你最好使用像:api这样的常规参数。 诚然,它不会匹配例如/api/asdf/asdf/users/1但如果你在api中嵌套资源,这是一个更好的解决scheme。

Ryan为什么不喜欢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 

其中有版本和通用命名路由的附加好处。 另外一个注意事项 – 使用时的惯例:module是使用下划线符号,例如: api/v1不是'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 

当然,你的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 

如果可能的话,我会build议重新考虑你的url,以便版本不在url中,但是放在accept头里。 这个堆栈溢出的答案很好:

API版本的最佳实践?

而这个链接显示了如何使用railspath来做到这一点:

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

我不是通过路由版本控制的忠实粉丝。 我们构build了VersionCake以支持更简单的API版本forms。

通过在我们各自的视图(jbuilder,RABL等)的文件名中包含API版本号,我们保持版本不显眼,并允许轻松降级以支持向后兼容性(例如,如果视图的v5不存在,我们渲染v4的视图)。

我不确定为什么你要redirect到一个特定的版本,如果没有明确要求版本。 看起来像你只是想定义一个默认版本,如果没有明确要求的版本就会被提供。 我也同意David Bock所说,保持URL结构的版本是支持版本控制的一种更简洁的方式。

无耻的插件:版本支持这些用例(和更多)。

https://github.com/bploetz/versionist

Ryan Bigg答案为我工作。

如果你也想通过redirect保持查询参数,你可以这样做:

 match "*path", to: redirect{ |params, request| "/api/v2/#{params[:path]}?#{request.query_string}" }