Come gestire gli errori in un ambiente API

5

Stiamo discutendo il modo migliore per gestire gli errori nelle chiamate a un metodo.

Abbiamo un modello di credito in cui consentiamo agli utenti di detrarre crediti per determinate azioni. Vorremmo effettuare una chiamata a:

User.DeductCredits(10);

Quindi il metodo Deduct controllerà cose come

  1. L'utente esiste?
  2. L'utente è attivo?
  3. L'utente ha almeno 10 crediti?

In caso contrario, questo risultato dovrebbe fallire.

Al momento stiamo scrivendo questo come una libreria di classi, ma proviamo a tenerlo aperto per convertirci in un servizio web in futuro. Le opzioni che abbiamo discusso finora sono:

  1. Genera un'eccezione quando si verifica un errore.
  2. Crea un nuovo oggetto risultato che T abbia il tipo di dati attesi e avvolgendolo con un codice di stato e un messaggio.

Non ci piaceva l'opzione n. 1, perché il codice per chiamare i crediti di deduzione sarebbe simile a:

try
{
   user.DeductCredits(10);
}
catch(InvalidUserException e)
{
}
catch(InactiveUserException e)
{
}
catch(CreditBalanceException e)
{
}

Inoltre, se trasformiamo questo in un servizio, non possiamo imporre eccezioni all'utente.

Il motivo principale per cui non è piaciuta l'opzione n. 2 è che sembrava che restituisse più dati di quelli di cui abbiamo bisogno. Ad esempio:

  var address = user.GetMailAddress();

Ora l'indirizzo ha il codice di stato e il messaggio, oltre a una proprietà dati o una proprietà valore. Quindi, per ottenere la città, avresti codice come:

if(!address.HasError)
   state = address.Data.State;

al contrario di:

state = address.State;

Quindi esiste una best practice per questo tipo di situazione? Un'opzione è davvero migliore dell'altra?

    
posta taylonr 20.12.2011 - 19:50
fonte

3 risposte

5

La migliore pratica è una combinazione dei due: se si tratta di un errore reale (qualcosa che non dovrebbe accadere realmente), allora dovresti lanciare un'eccezione. Se non è un errore reale, ma qualcosa che può accadere nel corso regolare delle cose, allora la funzione dovrebbe restituire una sorta di enum risultato. Nel tuo caso, senza conoscere le specifiche e solo indovinando dai nomi che vedo, mi sembra che "utente non valido" sia un errore, quindi un'eccezione dovrebbe essere generata, mentre "utente inattivo" e "fondi insufficienti" probabilmente non sono errori, ma risultati.

Suppongo che per "utente" intendi il programmatore che utilizzerà il tuo servizio. Nel mio libro, "non possiamo imporre eccezioni all'utente" è semplicemente sbagliato. devi forzare le eccezioni sull'utente; in effetti, l'utente si aspetta eccezioni quando le cose vanno male. Questo è il modo in cui sono fatte le cose in questo millennio. Inoltre, non ti preoccupare, molto raramente, se mai, dovrai scrivere più istruzioni catch per tutte le possibili eccezioni. Provalo e vedrai che negli scenari di utilizzo reali le cose non funzionano in questo modo.

    
risposta data 20.12.2011 - 20:47
fonte
3

Ho gestito questo problema andando avanti e generando eccezioni dove giustificato, e ho avuto la mia API (che capita di essere utilizzata su JSON, non sui servizi Web, ma non dovrebbe importare) restituire sempre un oggetto che ha una proprietà error, il numero del messaggio della chiamata originale e il valore restituito.

Il client che sto usando per consumare questo effettua la chiamata attraverso un livello che rimuove la risposta reale dall'oggetto restituito e genera un'eccezione sul client se la proprietà dell'errore ha un valore. Quindi, una volta scritto il livello client, l'esperienza di come funzionano le eccezioni è piuttosto naturale. Forse potrebbe funzionare per i tuoi futuri utenti API.

    
risposta data 20.12.2011 - 21:45
fonte
0

Voto per il numero 1: genera eccezioni.

E no, il tuo codice non dovrebbe cercare di catturare tutte le possibili eccezioni. Dovresti creare un codice per evitare la maggior parte di quelle eccezioni se puoi gestirlo. Invece del tuo esempio, considera questo:

if (user.Credits >= 10) { user.DeductCredits(10); }

Quando la tua applicazione arriva a questa parte del codice dovresti già essere certo che l'utente esista altrimenti cosa ci sarebbe in quella variabile utente?

    
risposta data 20.12.2011 - 20:52
fonte

Leggi altre domande sui tag