@jpgilldev / steid

steid/src/domain/error.rs
1.7 KBRaw
1use std::fmt;
2
3/// Every way a domain rule can be violated.
4///
5/// Deliberately coarse: a variant earns its place when a caller needs to react to it
6/// differently, not merely to describe a failure more precisely.
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum DomainError {
9 /// A value failed validation. Carries the field and the reason.
10 Validation { field: String, reason: String },
11 /// The requested entity does not exist.
12 NotFound { entity: &'static str },
13 /// The entity already exists and the operation requires it not to.
14 AlreadyExists { entity: &'static str },
15 /// Credentials did not match. Deliberately says nothing about which part failed.
16 InvalidCredentials,
17 /// The actor is known but not permitted to do this.
18 ///
19 /// Distinct from [`NotFound`](Self::NotFound): used where the resource is public
20 /// anyway, so pretending it does not exist would be theatre rather than privacy.
21 Forbidden,
22}
23
24impl DomainError {
25 pub fn validation(field: impl Into<String>, reason: impl Into<String>) -> Self {
26 Self::Validation {
27 field: field.into(),
28 reason: reason.into(),
29 }
30 }
31}
32
33impl fmt::Display for DomainError {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 match self {
36 Self::Validation { field, reason } => write!(f, "invalid {field}: {reason}"),
37 Self::NotFound { entity } => write!(f, "{entity} not found"),
38 Self::AlreadyExists { entity } => write!(f, "{entity} already exists"),
39 Self::InvalidCredentials => f.write_str("invalid credentials"),
40 Self::Forbidden => f.write_str("not permitted"),
41 }
42 }
43}
44
45impl std::error::Error for DomainError {}