ruby-on-rails 轨道管线的API版本控制

oknwwptz  于 2022-12-24  发布在  Ruby
关注(0)|答案(7)|浏览(141)

我试图像条纹版本我的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
vecaoik1

vecaoik11#

这证明了剥猫皮的方法不止一种。
我已经更新了答案,使用名称空间和301重定向--而不是默认的302。感谢pixeltrix和Bo Jeanes对这些事情的提示。
你可能想戴一个非常坚固的 Helm ,因为这会让你大吃一惊。
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,当你想要一堆作用域为一个特定路径和类似命名的模块的路由时,这是非常方便的。在这种情况下,我们希望namespace的块内的所有路由作用域为Api模块内的控制器,并且所有对该路由内的路径的请求都将以api为前缀。你知道吗?
在名称空间中,我们定义了另外两个名称空间(哇!),这次我们定义了“v1”名称空间,所以这里控制器的所有路由都将位于Api模块中的V1模块中:Api::V1。通过在此路由中定义resources :users,控制器将位于Api::V1::UsersController。这是版本1,您可以通过发出类似/api/v1/users的请求来到达该版本。
版本2只有一点小小的不同,服务于它的控制器不是Api::V1::UsersController,而是Api::V2::UsersController,你可以通过/api/v2/users这样的请求来实现。
接下来,使用match,这将匹配所有指向/api/v3/users之类的API路由。
这是我必须查找的部分。:to =>选项允许您指定一个特定的请求应该被重定向到其他地方--我知道这一点--但我不知道如何让它重定向到其他地方,并将原始请求的一部分与它沿着传递。
为此,我们调用redirect方法,并向其传递一个带有特殊插值的%{path}参数的字符串,当一个与最后的match匹配的请求到来时,它会将path参数插值到字符串中%{path}的位置,并将用户重定向到他们需要去的地方。
最后,我们使用另一个match来路由所有以/api为前缀的剩余路径,并将它们重定向到/api/v2/%{path},这意味着像/api/users这样的请求将转到/api/v2/users
我不知道如何使/api/asdf/users匹配,因为如何确定这应该是对/api/<resource>/<identifier>还是/api/<version>/<resource>的请求?

gdrx4gfi

gdrx4gfi2#

有几件事要补充:
你的重定向匹配对某些路由不起作用-*api参数是贪婪的,会吞噬掉所有的东西,例如/api/asdf/users/1将重定向到/api/v2/1。你最好使用一个常规的参数,比如:api。诚然,它不会匹配/api/asdf/asdf/users/1这样的情况,但是如果你在API中嵌套了资源,这是一个更好的解决方案。
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'。后者一度不起作用,但我相信它在Rails3.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
s3fp2yjn

s3fp2yjn3#

如果可能的话,我建议你重新考虑一下你的url,这样版本就不在url中了,而是放在accepts头中。
Best practices for API versioning?
这个链接展示了如何通过轨道布线实现这一点:
http://freelancing-gods.com/posts/versioning_your_ap_is

7cjasjjr

7cjasjjr4#

我不太喜欢通过路由进行版本控制,我们构建VersionCake是为了支持一种更简单的API版本控制形式。
通过在每个视图(jbuilder、RABL等)的文件名中包含API版本号,我们可以保持版本控制不引人注目,并允许轻松降级以支持向后兼容性(例如,如果视图的v5不存在,我们渲染视图的v4)。

vhipe2zx

vhipe2zx5#

我不知道为什么你要 * 重定向 * 到一个特定的版本,如果一个版本没有明确要求。似乎你只是想定义一个默认版本,得到服务,如果没有明确要求的版本。我也同意大卫博克,保持版本的URL结构是一个更清洁的方式来支持版本。
无耻插:Veristian支持这些用例(以及更多)。
https://github.com/bploetz/versionist

sshcrbum

sshcrbum6#

今天实现了这个,并找到了我认为在RailsCasts - REST API Versioning上“正确的方法”。如此简单,如此可维护,如此有效。
添加lib/api_constraints.rb(甚至不必更改vnd.example。)

class ApiConstraints
  def initialize(options)
    @version = options[:version]
    @default = options[:default]
  end

  def matches?(req)
    @default || req.headers['Accept'].include?("application/vnd.example.v#{@version}")
  end
end

像这样设置config/routes.rb

require 'api_constraints'

Rails.application.routes.draw do

  # Squads API
  namespace :api do
    # ApiConstaints is a lib file to allow default API versions,
    # this will help prevent having to change link names from /api/v1/squads to /api/squads, better maintainability
    scope module: :v1, constraints: ApiConstraints.new(version:1, default: true) do
      resources :squads do
        # my stuff was here
      end
    end
  end

  resources :squads
  root to: 'site#index'

编辑您的控制器(即/controllers/api/v1/squads_controller.rb

module Api
  module V1
    class SquadsController < BaseController
      # my stuff was here
    end
  end
end

然后,您可以将应用中的所有链接从/api/v1/squads更改为/api/squads,并且可以轻松实现新的API版本,甚至无需更改链接

ojsjcaue

ojsjcaue7#

瑞恩·比格的回答对我很有效。
如果您还希望在重定向过程中保留查询参数,可以这样做:

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

相关问题