ruby-on-rails - 使用不同 API 结果的设计模式

标签 ruby-on-rails api design-patterns

我有两个具有不同资源的 API:

  • www.api-A.com**/consumers,

    返回:{consumers: ['mike', 'Anna', 'Danilo']}

  • www.api-B.com**/clients,

    返回:{clients: ['Jack', 'Bruce', 'Mary']}

我想在一个 Controller 中使用这两个结果。我想像对待只有一个人一样对待他们。

我是否必须为每个 api 创建一个包装器,例如:

module ApiAWrapper
  #code here
end

module ApiBWrapper
  #code here
end

并在我的 Controller 中调用以下内容?

MyController
  def index
    @clients << ApiAWrapper.most_recent
    @clients << ApiBWrapper.most_recent
    @clients
  end
end

这样做,@clients 将是:

['mike', 'Anna', 'Danilo', 'Jack', 'Bruce', 'Mary']

这是使用具有相似响应的这些不同 API 的正确方法吗?是否有一种设计模式可供我使用或我应该阅读以指导我?

最佳答案

当我需要外部服务以通用方式响应时,我会实现一个解析器。在其他语言中,您可以使用接口(interface)来强制执行方法签名契约(Contract),but Ruby doesn't have this feature because of the duck typing .

这个解析器可以是一个函数或一个模块。例如:

module GitHub
  class Service
    BASE_URI = 'https://api.github.com'

    def self.fetch
      response = HTTP.get("#{BASE_URI}/clients")
      raise GitHub::ApiError unless response.ok?
      Parser.new(response).to_common
    end
  end

  class Parser
    def initialize(response)
      @response = response
    end

    def to_common
      json_response = JSON.parse(@response)
      json_response[:customers] = json_response.delete :clients
      # more rules
      # ...
      json_response
    end
  end
end

好的,到此为止。现在您已经有了一个服务,用于获取和处理 HTTP 部分,以及一个解析器,用于处理来自 HTTP 请求的响应主体。现在,假设您想使用另一个 API,例如 BitBucket API:

module BitBucket
  class Service
    BASE_URI = 'https://bitbucket.com/api'

    def self.fetch
      response = HTTP.get("#{BASE_URI}/customers")
      raise BitBucket::ApiError unless response.ok?
      Parser.new(response).to_common
    end
  end

  class Parser
    def initialize(response)
      @response = response
    end

    def to_common
      json_response = JSON.parse(@response)
      json_response[:clients] = (json_response.delete(:data).delete(:clients))
      # more rules
      # ...
      json_response
    end
  end
end

这样,您将使用相同的界面返回两个服务。要加入结果,您可以:

data = [GitHub::Service.fetch, BitBucket::Service.fetch, ...]
names = data.map { |customer_list| customer_list[:name] }
names.uniq

关于ruby-on-rails - 使用不同 API 结果的设计模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53140696/

相关文章:

ruby-on-rails - 是否可以登录到 Ruby on Rails 3 中的两个不同位置?

ruby-on-rails - Rails 3 - has_and_belongs_to_many

javascript api简化

ruby-on-rails - devise_token_auth forget password API 显示 Use POST/sign_in to sign in. GET is not supported 错误

javascript - 是否可以通过 Soundcloud API 从轨道的 ID 端点访问轨道的评论?

c# - 在哪里可以找到适配器模式的良好实现以及 C# 中的良好示例?

ios - 沿路径绘制图案

ruby-on-rails - Ruby on Rails 中的后端管理

ruby-on-rails - 我需要做什么才能将应用程序升级到最新的 Rails 版本?

java - 使用魔数(Magic Number) (1) 或全局常量检查列表大小?