La gestion des erreurs de son API est très importante pour que les consommateurs puissent avoir une description claire du problème mais c’est souvent fastidieux à maintenir.
On va voir comment avoir des statuts de réponse cohérent et des messages d’erreur parlant en utilisant uniquement nos exceptions.
Le cas d’exemple: dans un jeu, je ne peux pas construire de bâtiment si je n’ai pas les ressources requises à sa construction. Je veux que mon API renvoie un message d’erreur clair automatiquement sans avoir à faire de try / catch dans un contrôleur:
Message qu’on veut renvoyer au front:
Version utilisée pour l’article: .Net 9
Sommaire
Mise en place
On va créer une classe d’exception qui correspondra aux exceptions qu’on va automatiquement traiter avec notre futur filtre:
Dans mon cas, je veux que mes exceptions métier aient le code de retour “400” tout le temps avec un message d’erreur descriptif (et non pas toute la stack-trace comme c’est le cas par défaut).
Je vais créer une classe DomainException dont vont hériter les exceptions métier:
namespace Domain.Exception;
public class DomainException : System.Exception
{
protected DomainException(string? reason = null) =>
Reason = reason;
public string? Reason { get; }
}
Mon exception métier en hérite, ce qui donne:
namespace Domain.Exception;
public class NotEnoughResourceException(string message) : DomainException(message);
On va créer notre filtre .Net:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using StrategyBrowserGameAPI.Domain.Exception;
namespace StrategyBrowserGameAPI.Infrastructure.Primary.Exception;
public class HttpResponseExceptionFilter : IActionFilter, IOrderedFilter
{
public int Order => int.MaxValue - 10;
public void OnActionExecuting(ActionExecutingContext context) { }
public void OnActionExecuted(ActionExecutedContext context)
{
if (context.Exception is DomainException domainException)
{
context.Result = new ObjectResult(domainException.Reason)
{
StatusCode = StatusCodes.Status400BadRequest,
Value = domainException.Reason
};
context.ExceptionHandled = true;
}
}
Le code est très simple, si on a une DomainException, on dit qu’on renvoie une 400 avec la raison de l’exception.
Il ne nous reste plus qu’à enregistrer ce filtre dans notre Program.cs avant la lignevar app = builder.Build();
Et c’est tout ! Si on lance notre application et qu’une NotEnoughResourceException est throw, on aura bien la réponse attendue.
Pour aller plus loin
Si vous voulez personnaliser un peu plus les statuts d’erreur, vous pouvez faire des exceptions plus précises que DomainException. Par exemple BadFormatException qui va renvoyer des 400, un autre type pour d’autres status d’erreur. Un update rapide de la classe de filtre et le tour est joué !
public class HttpResponseExceptionFilter : IActionFilter, IOrderedFilter
{
public int Order => int.MaxValue - 10;
public void OnActionExecuting(ActionExecutingContext context) { }
public void OnActionExecuted(ActionExecutedContext context)
{
if (context.Exception is BadFormatException badFormatException)
{
context.Result = new ObjectResult(badFormatException.Reason)
{
StatusCode = StatusCodes.Status400BadRequest,
Value = badFormatException.Reason
};
context.ExceptionHandled = true;
}
else if (context.Exception is MyOtherException myOtherException)
{
context.Result = new ObjectResult(myOtherException.Reason)
{
StatusCode = StatusCodes.Status418BadRequest,
Value = myOtherException.Reason
};
context.ExceptionHandled = true;
}
}
}
L’idée c’est de choisir la granularité qui vous convient dans votre projet 🙂
On va voir comment avoir en quelques minutes des assertions qui vont vérifier les endpoints de notre API avec des scénarios de ce genre:
Feature: Create a new account
As a visitor,
I can create an account to access the game
Scenario: A visitor creates an account
When I fill the login form with
| email | password |
| [email protected] | Jh0...
Depuis .NET 9, le le support d’OpenAPI est directement inclus dans .NET et ne passe plus par les librairies Swagger par défaut (plus d’info sur ce choix ici si jamais ça vous intéresse).
De façons simplifiée, la librairie Swashbuckle.AspNetCore.Sw...
Description du problème
Par défaut, il n’est pas autorisé de faire des requêtes entre une application qui est dans un domaine A vers une autre qui serait dans un domaine B (pour des raisons de sécurité, il y a plus de détails dans les sources).
S...
Image prise sur Windows Central
Historique
Pour cet article je vais faire un mini REX sur l’écosystème de Microsoft pour les développeurs.
J’ai commencé à travailler avec les technologies Microsoft vers 2016. Pour situer, Windows 10 devait avoir �...