2013-06-21 26 views
10

Ho creato un oggetto di servizio in Rails per funzionare come interfaccia tra la nostra app e la nostra API.convalida e gestione degli errori per gli oggetti di servizio

ho avuto l'idea da http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/

Ecco un piccolo esempio:

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 

C'è un buon modello per la gestione di validazione e/o gettando errori per gli oggetti di servizio?

per le convalide:

  • devo controllare tutti gli ingressi per nullo o tipo sbagliato. C'è un modo per una facile convalida? Forse un'estensione di binari?

Per gli errori:

  • ho potuto prendere tutti gli errori API e poi tornare sani e salvi a zero. Ma il programmatore che utilizza l'oggetto servizio potrebbe non conoscere il significato di nil.
  • È possibile rilevare gli errori API e generare un altro errore, il che significa un ulteriore sforzo in tutte le funzioni
  • La terza opzione è lasciare così com'è e lasciare che il programmatore gestisca tutti gli errori dall'API.

Fatemi sapere se conoscete uno schema valido o se avete idee migliori per interfacciare un'API.

risposta

13

Per i casi più semplici (ad esempio con un solo argomento), quindi il check-and-raise con ArgumentError va bene. Non appena inizi ad avere casi complessi (più argomenti, oggetti, ecc.), Inizio appoggiandosi a Virtus e ActiveModel Validations.

Your linked article menziona effettivamente questi (vedere "Estrai oggetti modulo"). A volte uso qualcosa di simile per costruire oggetti di servizio, ad es.

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

Nella misura in cui eccezioni, li lascerei così com'è per azioni più piccole (come questa classe di servizio). I sarebbe avvolgerli se sto scrivendo qualcosa di più sostanziale, però, come un'intera libreria client API.

Non vorrei mai tornare indietro. Cose come un errore di rete o una risposta negativa o non riparabile dal server traggono vantaggio da errori espliciti.


Infine, c'è un approccio molto più pesante chiamato use_case. Anche se non lo usi, ha un sacco di idee su come affrontare gli oggetti di servizio, le convalide e i risultati che potresti trovare interessanti.

Modifica: Inoltre, controlla Mutations. Come use_case, ad eccezione di più semplice e meno completo.

+1

Grazie mille, questo è il tipo di risposta che stavo cercando! – ieldanr