服务对象的验证和错误处理

时间:2013-06-21 00:06:12

标签: ruby-on-rails validation interface error-handling soa

我在Rails中创建了一个服务对象,作为我们的应用程序和API之间的接口。

我从http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/

得到了这个想法

这是一个小例子:

class PackagesService
  def self.get_package(package_id)
    raise ArgumentError.new("package_id can't be nil") if package_id.blank?
    package = API::get "/packages/#{package_id}"
    package = JSON.parse package,
                          :symbolize_names => true unless package.blank?

  end
end

是否有任何良好的模式来处理验证和/或为服务对象抛出错误?

验证:

  • 我必须检查所有输入是否为错误类型。有没有办法轻松验证?也许是铁路扩展?

错误:

  • 我可以捕获所有API错误,然后安全返回nil。但是使用服务对象的程序员可能不知道nil的含义。
  • 我可以捕获API错误并引发另一个错误,这意味着在所有函数中执行此操作需要付出额外的努力
  • 第三个选项是保持原样并让程序员处理来自API的所有错误。

如果您知道任何好的模式,或者您有更好的想法来连接API,请告诉我。

2 个答案:

答案 0 :(得分:14)

对于简单的情况(例如,只有一个参数),那么使用ArgumentError进行检查和提升就可以了。一旦你开始有复杂的案例(多个参数,对象等),我就开始依靠VirtusActiveModel Validations

Your linked article实际上提到了这些(请参阅“提取表单对象”)。我有时会使用类似这样的东西构建服务对象,例如

require 'active_model'
require 'virtus'

class CreatePackage
  include Virtus
  include ActiveModel::Validations

  attribute :name, String
  attribute :author, String
  validates_presence_of :name, :author

  def create
    raise ArgumentError.new("Invalid package") unless self.valid?
    response = JSON.parse(
      API::post("/packages", self.attributes),
      :symbolize_names => true
    )
    Package.new(response)
  end
end

class Package
  include Virtus
  attribute :id, Integer
  attribute :name, String
  attribute :author, String
end

# eg.
service = CreatePackage.new(
  :name => "Tim's Tams",
  :author => "Tim",
)
service.valid? # true; if false, see service.errors
package = service.create

package.attributes
# => { :id => 123, :name => "Tim's Tams", :author => "Tim" }

就例外情况而言,我会将它们保留为较小的操作(如此服务类)。如果我正在写一些更重要的内容,我会 包装它们,例如整个API客户端库。

我永远不会只返回零。诸如网络错误或来自服务器的错误或不可解析的响应之类的事情都会受到明确错误的影响。


最后,有一个更重的方法叫做use_case。即使您不使用它,它也有很多关于如何处理您可能感兴趣的服务对象,验证和结果的想法。

修改:另外,请查看Mutations。和use_case一样,除了更简单,更不全面。

答案 1 :(得分:0)

我还为服务对象编写了一个gem。看看孔雀宝石。 (感谢@ rob-howard因为他的回答)