我有两个具有不同资源的 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/