Immagina un programma che espone un servizio REST / servizio GRPC / qualsiasi servizio, che utilizza diverse librerie di terze parti. Queste librerie possono ovviamente generare eccezioni se qualcosa va storto, ad esempio se l'utente tenta di accedere a qualcosa a cui non è permesso.
Il problema qui è che non è possibile controllare in anticipo se la richiesta è corretta o se l'utente ha abbastanza diritti. Quindi inviamo la richiesta alla libreria di terze parti e riceviamo un'eccezione.
È buona norma cogliere queste eccezioni al livello più alto e associarle a codici di stato come questo?
var statusCode = HttpStatusCode.InternalServerError;
if (ex is ArgumentException || ex is ResourceDoesntExistException)
statusCode = HttpStatusCode.BadRequest;
else if (ex is UnauthorizedAccessException)
statusCode = HttpStatusCode.Forbidden;
else if (ex is CustomerNotFoundException)
statusCode = HttpStatusCode.NotFound;
e quindi restituire il codice di stato con un oggetto di errore:
return new ErrorResponse
{
Error = new ErrorDescription
{
Message = ex.Message,
Type = ex.GetType().Name
}
};
Vantaggi che vedo usando questo approccio:
- Nel programma, non dobbiamo preoccuparci se esponiamo un servizio REST o un servizio SOAP o altro. Basta lanciare un'eccezione, verrà gestita correttamente in seguito.
- Il chiamante riceve informazioni sufficienti e corrette se qualcosa va storto (a condizione che le eccezioni abbiano nomi e informazioni significativi).
- La registrazione può anche essere centralizzata. Tutte le eccezioni non gestite verranno registrate nel punto in cui vengono convertite in risposte di errore.
Svantaggi:
- Sembra un po '"hacky".
Qual è il modo corretto per farlo?
Modifica: dal momento che è stato richiesto, ecco cosa faccio per i servizi gRPC, in cui la mappatura degli errori è abbastanza simile:
private RpcException GenerateRpcException(Exception ex)
{
var statusCode = StatusCode.Unknown;
if (ex is ArgumentException || ex is ResourceDoesntExistException)
statusCode = StatusCode.InvalidArgument;
else if (ex is UnauthorizedAccessException)
statusCode = StatusCode.PermissionDenied;
else if (ex is CustomerNotFoundException)
statusCode = StatusCode.NotFound;
var status = new Status(statusCode, ex.Message);
var exceptionName = ex.GetType().Name;
var rpcMetadata = new Metadata
{
{ "exception_name", exceptionName }
};
return new RpcException(status, rpcMetadata);
}