2013-06-21 37 views
10

Utworzono obiekt usługowy w Railsach, aby działał jako interfejs między naszą aplikacją a naszym API.sprawdzanie poprawności i obsługa błędów dla obiektów usługowych

wpadłem na pomysł z http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/

Oto mały przykład:

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 

Czy istnieje jakiś dobry wzór do obsługi walidacji i/lub rzucanie błędy w obiekty usług?

Dla walidacji:

  • muszę sprawdzić wszystkie wejścia do zera lub niewłaściwego typu. Czy istnieje sposób na łatwą walidację? Może rozszerzenie szyn?

Dla błędów:

  • mogłem złapać wszystkie błędy API, a następnie bezpiecznie wrócić na zero. Ale programista używający obiektu usługi może nie znać znaczenia zer.
  • Mogłem złapać błędy API i zgłosić inny błąd, co oznacza dodatkowy wysiłek, aby to zrobić we wszystkich funkcjach
  • Trzecią opcją jest pozostawić tak, jak jest, i pozwolić programistowi obsłużyć wszystkie błędy z API.

Daj mi znać, jeśli znasz jakiś dobry wzór lub masz lepsze pomysły na interfejs API.

Odpowiedz

13

W prostych przypadkach (np. Za pomocą tylko jednego argumentu), twoje sprawdzanie i podbijanie z ArgumentError jest w porządku. Gdy tylko zaczniesz tworzyć złożone sprawy (wiele argumentów, obiektów itp.), Zacznę opierać się na Virtus i ActiveModel Validations.

Your linked article faktycznie wspomina o nich (patrz "Wyciąganie obiektów formularzy"). Czasami używam czegoś takiego do konstruowania obiektów usługowych, np.

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" } 

W przypadku wyjątków, zostawiłbym je w stanie, w jakim się znajdują, dla mniejszych działań (takich jak ta klasa usług). I będzie je zawijać, jeśli piszę coś bardziej znaczącego, takiego jak cała biblioteka klientów API.

Nigdy nie wrócę po prostu zero. Rzeczy, takie jak błąd sieci lub zła lub nieodwracalna reakcja serwera, korzystają z wyraźnych błędów.


Wreszcie, istnieje znacznie cięższe podejście o nazwie use_case. Nawet jeśli go nie używasz, ma kilka pomysłów, jak radzić sobie z obiektami usług, walidacjami i wynikami, które mogą Cię zainteresować.

Edytuj: Sprawdź również Mutations. Podobnie jak use_case, z wyjątkiem prostszych i mniej obszernych.

+1

Dziękuję bardzo, oto rodzaj odpowiedzi, której szukałem! – ieldanr