1

现在我有两个 API 命名空间,Api::V1 和 Api::V2

我计划随着时间的推移慢慢实施 V2,而不是一次性完成。但是,由于它的一部分存在,我希望客户端可以将所有 HTTP 请求发送到 V2 URL,并在该特定端点尚未实现的情况下让服务器处理它。

如果 V2 控制器没有操作,有没有办法将 V2 请求路由到 V1 控制器?

简单示例:

路线:

namespace :api do
    namespace :v1 do
        resources :items, only: [:index]
    end
    namespace :v2 do
        resources :items, only: :create
    end
end

将产生以下端点:

  1. 获取 /api/v1/项目
  2. 发布 /api/v2/项目

目标是向 /api/v2/items 发送一个 GET 请求并让它调用 Api::V1:ItemsController#index,因为 V2 控制器还没有这个方法。

4

2 回答 2

1
namespace :api do

    namespace :v1, path: "v2" do
        # All endpoints that are on v1 of API
    end

    namespace :v2 do
        # All endpoints that are on v2 of API
    end

end

如果您在此处运行 rake 路由,您会看到它们都与路由“api/v2/____#_____”匹配,但顶部块中的调用 Api::V1 动作,底部块调用 Api::V2 动作,所以在实现这些端点时,您必须将它们从顶部移动到底部

于 2016-08-10T19:37:02.253 回答
0

我也有一个版本化的 API。我还没有碰到下一个版本。但我想我会分享我计划做的事情。这可能有点毛骨悚然。我有一种感觉,这对我(思考我的计划)比对你更有用。所以,很抱歉。但是,这里...

在开始之前,我应该说我对控制器操作采取了不同的方法。在我的应用程序中,我喜欢将我的控制器操作委托给我称之为“经理”的普通旧 ruby​​ 对象。每个控制器都有一个“manager_base”。所以,在我的控制器中,我有这样的东西:

class ApplicationController < ActionController::Base

  private

  def do_action(action=nil)
    action ||= caller[0][/`.*'/][1..-2]
    manager.send("manage_#{action}", self, cookies, request)
  end

  def manager
    base = self.class.name.split('::')
    base.pop
    base << "#{controller_name.camelize}Managers::ManagerBase"
    base.join('::').constantize
  end

end 

class Api::V1::FooController < ApplicationController

  def index
    do_action
    render_result
  end

end

然后我也有:

class ManagerBase
  class << self

    def manage_index(controller, cookies, request)
      sub_out("Index", controller, cookies, request)             
    end

    def manage(controller, cookies, request)
      new(controller, cookies, request).manage
    end

  private

    def sub_out(method, controller, cookies, request)
      sub_manager(method).manage(controller, cookies, request)   
    end

  end # Class Methods

  def initialize(controller, cookies, request)
    @controller = controller
    @cookies = cookies
    @request = request
  end

end

class Api::V1::FooManagers::ManagerBase < ManagerBase
  class << self

    private

    def sub_manager(method)
      "Api::V1::FooManagers::#{method}Manager".constantize
    end  

  end # Class Methods
end

class Api::V1::FooManagers::IndexManager < Api::V1::FooManagers::ManagerBase
  def manage
    ... do stuff
  end
end

如果您跟随弹跳球,以下是我的应用程序流程:

  • index被召唤Api::V1::FooController
  • index调用do_action(继承自ApplicationController),后者又调用manager(也继承自ApplicationController
  • manager返回Api::V1::FooManagers::ManagerBase
  • do_actionmanage_index然后调用Api::V1::FooManagers::ManagerBase
  • manage_indexsub_out依次调用的调用sub_manager
  • sub_manager返回Api::V1::FooManagers::IndexManager
  • sub_outmanage然后调用Api::V1::FooManagers::IndexManager
  • manage(类方法 - 从 ManagerBase 继承)创建一个新实例,Api::V1::FooManagers::IndexManager然后在新实例上调用manage(实例方法)。

可能会或可能不会很明显,当我移至 Api::V2 时,我有两次机会“挂钩”回我的经理的 Api::V1 版本(这相当于使用我的 V1 控制器方法 - 你的原始问题)。

首先,如果我还没有实现Api::V2::FooManagers::ManagerBase,我可以ApplicationController.manager回退到ManagerBase(ie, Api::V1::FooManagers::ManagerBase) 的最后一个实现版本。在这种情况下,我将使用所有Api::V1::FooManager子管理器(如IndexManager)。

其次,如果我已经实施Api::V2::FooManagers::ManagerBase但尚未实施Api::V2::FooManagers::IndexManager,那么我可以Api::V2::FooManagers#sub_manager退回到Api::V1::FooManagers::IndexManager.

好吧,我现在要停下来了。感谢您有机会大声思考这个问题。抱歉,如果它完全没用,很热。

于 2016-08-09T23:08:40.010 回答