Odori nella gestione delle eccezioni: come separare tra le eccezioni pubbliche e interne?

1

Durante lo sviluppo di una piccola API Web, abbiamo deciso di separare le eccezioni interne dalle eccezioni pubbliche. Le eccezioni pubbliche sono eccezioni HTTP, che si traducono in risposte HTTP con codice di stato appropriato (ad esempio BadRequestHttpException , NotFoundHttpException , ecc.). Le eccezioni interne sono eccezioni generate dagli adattatori nel nostro sistema (livello cache, livello di persistenza, ecc.) O nel dominio ( InvalidUserException , BadPasswordException , ecc.).

Questo è stato grandioso finora. Tuttavia, i nostri controllori stanno iniziando a sentire un cattivo odore:

    try {
        securityService.login(credentials);
    } catch (InvalidOAuthProviderException e) {
        throw new BadRequestHttpException(e.getMessage(), e.getCode());
    } catch (UserNotFoundException e) {
        throw new NotFoundHttpException(e.getMessage(), e.getCode());
    } catch (InactiveUserException e) {
        throw new NotFoundHttpException(e.getMessage(), e.getCode());
    } catch (InvalidOAuthTokenException e) {
        throw new ForbiddenHttpException(e.getMessage(), e.getCode());
    }

La firma del costruttore HttpException è il messaggio di errore e il codice. Ciò comporterà un corpo JSON: {"message":"","code":222} . Il codice è il codice di errore univoco per il riferimento del documento. Il codice HTTP della risposta effettiva è definito dal tipo di eccezione.

Questo non è chiaramente un buon segno e sono sicuro che c'è qualcosa di sbagliato nel design qui. Qualsiasi aiuto?

    
posta Klaus S. 17.02.2015 - 14:06
fonte

2 risposte

3

Stai gestendo gli errori attraverso il confine tra due sistemi, in modo efficace, quindi è meglio pensare al gestore HTTP come a un sistema e alla logica interna che genera queste eccezioni interne come una libreria.

Dato che vuoi prenderli al punto limite e non vuoi mappare le eccezioni interne a quelle esterne, allora ti rimane un semplice catch-all (o un paio di catch). Il client non vuole conoscere l'eccezione interna, quindi prendere tutto da una richiesta di accesso e restituire un'eccezione di richiesta proibita o non valida è la strada da percorrere, considerando che includi il messaggio di errore dall'eccezione interna, in realtà non è così importa quale sia l'eccezione interna per quanto riguarda l'interfaccia client - qualcosa è andato storto, è stato un cattivo utente o qualche errore del server.

Nella maggior parte dei casi, dovresti catturare gli errori interni ed eseguire qualche altra forma di handler su di loro, ad esempio registrarli o sollevare un allarme di amministrazione, e quindi restituire un'eccezione più generica "non ha funzionato" al client . L'unica differenza qui è che le eccezioni che conosci sono "previste", ad esempio un errore di accesso a causa di una password errata.

    
risposta data 17.02.2015 - 14:33
fonte
0

È possibile creare una classe di utilità riutilizzabile che risolverà l'HttpException corretta.

try {
        securityService.login(credentials);
    } catch (InternalException e) {
        throw ExceptionUtil.resolveHttpException(e);
    }      

public class ExceptionUtil {
  public static HttpException resolveHttpException(InternalException exc) {
     if (exc instanceOf InvalidOAuthProviderException) 
        return new InvalidOAuthProviderException(e.getMessage(), e.getCode()
     else if (exc instanceOf AnotherInternalException)
        return new  AnotherInternalException;
      ...
    }

}

Quindi puoi usarlo su tutte le applicazioni senza ridondanza di codice.

    
risposta data 17.02.2015 - 14:16
fonte

Leggi altre domande sui tag