Gestione di convalide / risposte di eccezione nell'app restante

2

Quindi sto affrontando un problema con la gestione di tutti i tipi di eccezioni all'interno di spring-boot applicazione. Fondamentalmente il progetto è strutturato:

back-end (services, repositories) < ----- RestControllers < ---- UI (React\Angular)

L'essenza è che UI dipende da Rest API wile resto API dipende da Back-end services

Ora - Rest API è progettato attorno ai propri servizi RISORSE e back-end attorno ai propri DTO . La convalida attuale viene eseguita in due punti: RestControllers e Services mentre UI mostra solo le risposte (errori di convalida).

Problema: Il solito problema di validazione in RestController sta acquisendo resource valido. E questo è gestito bene con la combinazione di @Valid , JSR 303 Bean Validation e @ControllerAdvice . E questo si traduce in qualcosa di simile: [ field: ... , error: ... ] ... Ma per quanto riguarda altri problemi? Eccezioni al vincolo DB, ad es. ? Pertanto, la convalida può essere eseguita anche in service layer, ma le eccezioni non seguono più lo stesso standard di [ field: ... , error: ... ]. Anche l'eccezione generata da service deve essere tradotta in una risposta specifica RESOURCE . Ora c'è più di una risorsa di errore e questo continuerà a crescere.

Data la situazione simile, quali sono le migliori pratiche in tale situazione?

    
posta Xeperis 26.08.2016 - 09:59
fonte

1 risposta

1

Darò un esempio usando Spring REST dato che ha una gran pratica di funzionalità incorporata per gestire questo problema ed è probabilmente l'implementazione Java REST più popolare in circolazione al momento. Una strategia consiste nell'utilizzare Spring @ Annotazione ControllerAdvice . Ciò consente di annotare una classe contenente la logica di traduzione delle eccezioni per gestire le eccezioni che si presentano durante l'elaborazione di una richiesta.

I metodi all'interno della classe possono quindi essere annotati con @ ExceptionHandler e @ResponseStatus , per definire la logica per varie eccezioni.

Ad esempio, se vogliamo gestire un'eccezione generata quando la chiamata REST non riesce a individuare una risorsa dal livello di persistenza come descritto nella domanda ...

    @ExceptionHandler(EmptyResultDataAccessException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public SimpleErrorModel handleEmptyDataException(HttpServletRequest request, Exception exception) {
        LOGGER.debug(exception);
        return new SimpleErrorModel("Resource not found");
    }

O se viene lanciata una DataIntegrityViolationException ...

    @ExceptionHandler(DataIntegrityViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public SimpleErrorModel handleDataIntegrityViolationException(HttpServletRequest request, Exception exception) {
        LOGGER.debug(exception);
        return new SimpleErrorModel("Data integrity violation");
    }

In questo modo, quando viene lanciata un'eccezione, Spring localizzerà la classe appropriata contrassegnata con l'annotazione @ControllerAdvice e quindi cercherà il metodo di traduzione delle eccezioni corretto. Risolve questo metodo ed esegue la logica nel metodo. Ecco, ho una classe SimpleErrorModel che assomiglia a questo ...

public class SimpleErrorModel {

    private String errorMessage;
    private String moreInfo;

    public SimpleErrorModel(String errorMessage) {
        this(errorMessage, "");
    }

    public SimpleErrorModel(String errorMessage, String moreInfo) {
        this.errorMessage = errorMessage;
        this.moreInfo = moreInfo;
    }
}

... che viene serializzato tramite Spring REST e restituito al front-end con il codice di risposta corretto. Puoi anche passare l'oggetto HttpResponse al metodo e fare quello che vuoi con esso.

Questa è solo una strategia, ma ha il vantaggio di mantenere tutta la tua logica di gestione degli errori e dovrebbe essere assolutamente valida per il 90% dei casi d'uso. Se hai bisogno di un controllo più preciso, puoi aggiungere qualificatori all'annotazione @ControllerAdvice ...

    @ControllerAdvice(annotations = RestController.class)

... per limitare le classi annotate utilizzate per questo gestore.

    
risposta data 26.08.2016 - 10:57
fonte

Leggi altre domande sui tag