jezzsantos / saastack

A comprehensive codebase template for starting your real-world, fully featured SaaS web products. On the .NET platform
The Unlicense
45 stars 13 forks source link

Review control flow decision #9

Closed jezzsantos closed 1 year ago

jezzsantos commented 1 year ago

We've already discussed that exceptions are okay to throw from deep within the code for exceptional reasons.

However, there is a class of errors that we do expect from API's. For example, "aggregate not found" which should be translated to a 404 -Not Found response, with an optional reason.

There are many more of these kinds of things, RuleViolation, RoleViolation are two others we could expect frequently.

The question is, what is a reasonable design improvement here (that is an improvement on raising exceptions, and is not to esoteric), for some kind of result type that we could bubble up from the Domain/Application layers that the API layer can translate into HTTP status codes?

We don't want to do this for the hell of it, and certainly not to name any claims about moving more functional.

Solutions

One common solution is to use a Result<TResult> type where you can either return the expected result (including no result) and also return either an exception, and/or some well defined error type. The error type would have to be good enough to tell the whole story (e.g. code + reason). and we could define some pretty standard ones.

The exception could be there in case you want to raise one. But in general, you would just throw the exception, and the runtime would catch it at the API layer, and convert it to a 500 - Internal Server Error in all cases - since it is unexpected.

What could be another solution?

Problems to avoid

jezzsantos commented 1 year ago

LanguageExt contains a Result class that can be used.