【问题标题】:Where do API calls go in a ruby on rails MVC framework project?API 调用在 ruby​​ on rails MVC 框架项目中去哪里?
【发布时间】:2013-02-18 18:43:54
【问题描述】:

我有一个带有 mvc 框架的 Ruby on Rails 应用程序。截至目前,我在控制器中有 API 调用,但不认为这是适合他们的地方。我的所有 API 调用都应该放入什么样的文件?谢谢

def getDetails(id)
 api_response = HTTParty.get(base_uri, :query => {:DID => id, :DeveloperKey => devKey})
 @json_hash = api_response.parsed_response
 return @json_hash
end

【问题讨论】:

  • “API 调用”是什么意思?
  • 请提供您关心的控制器代码示例。
  • 如果它们是外部 API 调用,我的想法是它们应该被视为数据并放置在模型中。这样,您可以轻松地添加到数据库(用于节流)并保留 SoC。只是我的想法,我也看到外部调用作为 lib 中的声明类。
  • 我添加了控制器代码。它们是外部 API 调用
  • 既然您似乎已经定义了用于进行调用的方法,为什么不将它们全部放在一个类中并在您的控制器中使用它。

标签: ruby-on-rails api


【解决方案1】:

根据我的编码风格(以及对 MVC 的理解),外部调用将被放置在“无表”模型中。 RailsCasts 193 谈到了这个概念,Rails 4 支持不那么笨重的语法。如果您需要对代码进行任何操作,模型似乎是放置这些的合乎逻辑的地方。将这些方法移到控制器中是可行的,但随着应用程序的增长可能会产生问题。

外部 API 调用的另一个考虑因素实际上是将它们存储在数据库中,此时肯定应该在模型中,所以(对我来说)很清楚这些确实应该在模型中。

【讨论】:

  • Rails 3 已经对无表模型提供了更好的支持。耶胡达·卡茨wrote a good blog post on it.
  • “无表模型”听起来好像你会用你的 API 包装器拖着一堆不必要的代码。 (验证?属性?等)只需使用 PORO。 (普通的旧红宝石对象)。为什么你需要的不仅仅是一门课?
【解决方案2】:

对外部服务(第三方)的 API 调用并不特定于您的应用,因为每个人都可以使用它们的服务(理论上)。据我了解,这些功能都放在lib/ 目录中,因为它们不是特定于应用程序的。理想情况下,您可以从项目中的lib 中提取代码,并将其放到另一个项目中其他人的lib/ 中,它仍然可以正常工作。

拨打lib/。如果需要,您可以根据控制器中返回的数据创建模型。

看起来像这样:

应用程序/控制器/

class YourController < ApplicationController

  def getDetails
   # keep in mind, api call may fail so you may want surround this with a begin/rescue
   api_response = YourApiCall.new.get_details(params[:id])
   # perhaps create a model
   @model = SomeModel.new(fname: api_response[:first_name], lname: api_response[:last_name])
    # etc...
  end
end

lib/

require 'HTTParty'

Class YourApiCall
  def get_details(id)
    HTTParty.get(base_uri, :query => {:DID => id, :DeveloperKey => devKey})
    @json_hash = api_response.parsed_response
    return @json_hash
  end
end

【讨论】:

  • 试过这个,但类没有被加载。我最终只是把它放在模型中。另一个问题(除非我弄错了)是您在声明中将 class 中的 C 大写。
  • 要加载 /lib 目录中的文件,请将以下内容添加到 config/application.rbconfig.autoload_paths += %W(#{config.root}/lib)。检查edgeguides.rubyonrails.org/…了解更多信息。
  • 您也可以通过将require 'your_api_call' 放在您希望加载的控制器顶部来加载该类
【解决方案3】:

这个很晚,但我想我会添加我的 2p/2c。

除了控制器代码之外,我喜欢尽量让控制器保持清洁,我根据请求类型和参数将其松散地定义为程序流代码。例如,为请求类型选择正确的模板或根据用户是否登录选择正确的调用方法。

在计算响应时,我不喜欢在控制器中乱扔大量操纵模型和设置实例参数的代码。这很难测试,甚至更难重复使用。我更喜欢推迟到另一个对象并将单个值对象返回给模板。

有时我可以遵循一个模型:也许这是一个简单的查找,我只是将一个模型或一组模型发送到模板。

也许我在模型中实现了一个有用的方法来返回适当的值或值对象。

但是,有时我正在做一些不使用模型的事情,或者使用多个模型,或者感觉它实际上不应该弄乱模型。在这种情况下,控制器和模型都不适合放置代码。

lib 目录也感觉不对。我倾向于将 lib 目录视为包含我还没有费心变成 gem 的代码的地方。如果我正在编写的代码仅在应用程序的上下文中有意义,那么它就不太合适。

所以我转向服务对象。在“应用程序”文件夹下,我有一个“服务”文件夹,其中包含封装单个站点行为块的小型功能类。 (或者有时,协调几个其他服务为控制器提供一个简单的接口。)

这让我可以精简我的控制器和模型,并且是放置需要联系 API 的代码的理想场所。

如果您想更进一步,您可以将 API 本身包装在一个包装类(或一组类)中,并将它们保存在 lib 目录中(以便以后转换为 gem)。然后服务对象将执行使用适当的值(从控制器传递)调用 API 包装器的任务,并使用模板可以干净地询问的内容进行响应。

当然,您可以比这更进一步并添加更多层。例如,表示层可以位于服务对象(提供通用值)和特定视图的格式数据之间。 (也许您想同时提供网页和 RSS 提要,例如它们需要不同的日期格式。)

但你明白了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多