UC-07 · Un aggregate introuvable est un échec explicite
Signal
- Un use case qui appelle une méthode sur le résultat d’un finder sans vérifier qu’il existe.
- Une assertion
!sur ce résultat. - Une
TypeErrorsurundefinedqui finit en erreur 500.
Pourquoi
L’absence est une issue que l’appelant doit traiter, comme n’importe quel refus. Chaque handler la vérifie juste après le chargement, et renvoie une erreur nommée d’après ce qui manque.
Exceptions
Un use case où l’absence est une issue normale, comme une recherche qui peut ne rien trouver.
Correction
Le repository renvoie undefined quand l’aggregate n’existe pas (get(id)), et le handler le transforme en erreur nommée juste après le chargement.
Adaptation
Avec strictNullChecks, un finder typé T | undefined impose la vérification à la compilation.
Notre choix : l’absence est une erreur métier renvoyée dans un Result (WalletNotFound), que driving traduit en 404.
Voir aussi
REP-03 (les erreurs de stockage ne sortent pas du repository), UC-02.
Exemple
async handle(command: BlockWalletCommand): Promise<Result<void, BlockWalletError>> {
// walletId, reference and directions: the command parsed into value objects
return this.#unitOfWork.run(async () => {
const wallet = await this.#wallets.get(walletId);
if (!wallet) {
return err(new WalletNotFound(walletId));
}
const blocked = wallet.block(reference, directions, this.#clock.now());
if (!blocked.ok) {
return blocked;
}
const saved = await this.#wallets.save(wallet);
if (!saved.ok) {
return saved;
}
await this.#outbox.append(wallet.pullEvents());
return ok();
});
}Le wallet introuvable devient WalletNotFound dès le chargement, avant tout appel sur lui, et driving le traduit en 404.