Imaginez un programme qui expose un service REST/ service gRPC /quel que soit le service, qui utilise plusieurs bibliothèques tierces. Ces bibliothèques peuvent bien sûr lever des exceptions en cas de problème, par exemple, si l'utilisateur a essayé d'accéder à quelque chose auquel il n'est pas autorisé.
Le problème ici est qu'il n'est pas possible de vérifier au préalable si la demande est correcte ou si l'utilisateur a suffisamment de droits. Nous envoyons donc la demande à la bibliothèque tierce et obtenons une exception.
Est-ce une bonne pratique d'attraper ces exceptions au niveau supérieur et de les mapper à des codes d'état comme celui-ci?
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;
puis renvoyez le code d'état avec un objet d'erreur:
return new ErrorResponse
{
Error = new ErrorDescription
{
Message = ex.Message,
Type = ex.GetType().Name
}
};
Avantages que je vois en utilisant cette approche:
Désavantages:
Quelle est la bonne façon de procéder?
Edit: Depuis qu'il a été demandé, voici ce que je fais pour les services gRPC, où le mappage d'erreur est assez similaire:
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);
}
Il n'y a rien de mal à normaliser les exceptions et à les gérer correctement. Votre classe ErrorResponse
semble être la bonne approche pour gérer un appel à votre service REST.
S'il y a quelque chose ici qui pourrait être amélioré, c'est une approche de gestion des erreurs statiques. La liste des exceptions/codes d'erreur possibles pourrait facilement s'allonger demain et votre autre va devenir monstrueux à ce rythme.
Pensez à créer une classe ErrorManager
contenant une liste d'interfaces ErrorHandler
avec deux méthodes: bool CanHandle(Exception)
et ErrorResponse Handle(Exception)
Votre ErrorManager
lorsqu'il reçoit une exception vérifiera bêtement chaque ErrorHandler
enregistré avec un appel à CanHandle
à l'exception. Lorsqu'il renvoie true, la vérification s'arrête et vous retournez votre ErrorHandler
en appelant la méthode Handle
de votre gestionnaire. Vous créez ensuite un ErrorHandler
pour chaque ErrorResponse
possible (et pas nécessairement pour chaque exception).
Cette approche dynamique vous donne la possibilité d'enregistrer par programme les classes ErrorHandler
ou de les charger à partir d'une base de données si vous le souhaitez. Plus important encore, si vous décidez d'enregistrer par programme les classes ErrorHandler
maintenant, si vous décidez de changer la façon dont vous chargez ces gestionnaires, vous pouvez le faire avec peu ou pas d'impact sur votre programme tel quel. Essentiellement, vous protégez votre gestion des erreurs dans le futur.
Un mot au sage: ayez un plan pour quand vous ne trouvez aucun gestionnaire pour une exception. Il vaut probablement mieux être un HttpStatusCode.InternalServerError
. Bien que vous puissiez créer un gestionnaire qui "gère toujours" les exceptions, je le déconseille, car techniquement, nous parlons de gérer conn les exceptions possibles et toute exception qui n'est pas attendue est une exception inconnue et devrait très certainement être signalée en rouge et non pas simplement traitée comme toute autre erreur.
J'aime votre approche, sauf que je traduirais également ce qui va au client dans le corps de la réponse d'erreur. Comme vous dites que vous n'avez aucun contrôle sur les bibliothèques tierces, vous ne savez pas non plus si elles vont divulguer des informations sensibles au client. Mieux vaut prévenir que guérir: enregistrez l'exception dans vos journaux internes et propagez uniquement le minimum d'informations dont le client a besoin pour connaître l'erreur.