Im working on a project where adapters never raise Exceptions. Instead, it returns a Result object like this:
Dto = TypeVar("Dto", bound=BaseModel)
class BaseError(BaseModel):
error_code: DomainErrorEnum
message: str
def raise_error(self):
raise ErrorMap[self.error_code] # Here is the big deal
class Result(BaseModel, Generic[Dto]):
error = Optional[BaseError]
data: Optional[Dto]
Where DomainErrorEnum is an Enum that maps slugs that represent our DomainErrors.
What I like to do is a ErrorMap class that works like this:
class ErrorMap(DomainErrorEnum, Enum):
DomainErrorEnum.GENERIC_ERROR = GenericErrorException
DomainErrorEnum.NOT_FOUND = CartNotFoundException
DomainErrorEnum.OUT_OF_STOCK = OutOfStockException
Doing this, I have 2 things well segregated:
- An Enum (actually we have many
"DomainErrorEnum", but Im pretending here that we have only one to make my example easy to understand) that has the responsability to represents (slugs) all my domain errors - A class that know which Exception it should throw whatever I want to trhow it (remember, my adapters never raise anything, it always return a
Result[SpecificDto]object
Any idea on how to represent these 2 things?
Just for clarify:
# On domain module:
def specific_use_case():
result_search: Result[ProductDto] = adapter.search_product()
if product_dto.is_success:
data: ProductDto = result_search.data
result_search.business_rules_method(data) # Here, on pure business rules we throw exceptions without using our map, because here we dont use these Result pattern
return entity
result_search.error.raise_error()
>Solution :
ErrorMap should probably be a map (a dictionary):
ERROR_MAP = {
DomainErrorEnum.GENERIC_ERROR: GenericErrorException,
DomainErrorEnum.NOT_FOUND: CartNotFoundException,
DomainErrorEnum.OUT_OF_STOCK: OutOfStockException
}