Repository navigation
Expand file tree
/
Copy pathErrors.cs
More file actions
70 lines (66 loc) · 3.83 KB
/
Copy pathErrors.cs
File metadata and controls
70 lines (66 loc) · 3.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
using ManagedCode.Communication;
namespace KeyLoad;
/// <summary>Creates standard status mappings, problem details, and KeyLoad exceptions.</summary>
public static class Errors
{
private const string ProblemTypePrefix = "urn:keyload:error:";
private const string InvalidDomainProblem = "The database command problem is invalid.";
/// <summary>Reads the exact domain error from a execution problem, or returns null for success.</summary>
/// <param name="problem">The execution problem associated with the database result.</param>
/// <returns>The validated domain code, or null when no problem exists.</returns>
public static ErrorCode? Code(Problem? problem)
{
if (problem is null)
{
return null;
}
if (!Enum.TryParse<ErrorCode>(problem.ErrorCode, out var code) || !Enum.IsDefined(code)
|| problem.ErrorCode != code.ToString() || problem.Title != code.ToString() || problem.Type != $"{ProblemTypePrefix}{code}"
|| problem.StatusCode != Status(code) || string.IsNullOrWhiteSpace(problem.Detail))
{
throw Fail(ErrorCode.Corruption, InvalidDomainProblem);
}
return code;
}
/// <summary>Returns the HTTP status code associated with an error code.</summary>
/// <param name="code">Specifies the code value.</param>
/// <returns>The requested value.</returns>
public static int Status(ErrorCode code) => code switch
{
ErrorCode.NotFound => (int)System.Net.HttpStatusCode.NotFound,
ErrorCode.PermissionDenied => (int)System.Net.HttpStatusCode.Forbidden,
ErrorCode.Unauthenticated => (int)System.Net.HttpStatusCode.Unauthorized,
ErrorCode.Conflict or ErrorCode.RevisionConflict or ErrorCode.DuplicateEventId or ErrorCode.StaleLease => (int)System.Net.HttpStatusCode.Conflict,
ErrorCode.ResourceExhausted or ErrorCode.BudgetExceeded => (int)System.Net.HttpStatusCode.TooManyRequests,
ErrorCode.UnsupportedCapability => (int)System.Net.HttpStatusCode.UnprocessableEntity,
ErrorCode.UnknownWriteOutcome or ErrorCode.RecoveryRequired or ErrorCode.OwnershipLost or ErrorCode.ClockUncertain => (int)System.Net.HttpStatusCode.ServiceUnavailable,
_ => (int)System.Net.HttpStatusCode.BadRequest
};
/// <summary>Creates a problem detail with the standard status for an error code.</summary>
/// <param name="code">Identifies the domain error code.</param>
/// <param name="detail">Provides safe caller-visible error detail.</param>
/// <returns>The standard problem details for the error code.</returns>
public static Problem Problem(ErrorCode code, string detail) => new()
{
Type = $"{ProblemTypePrefix}{code}",
Title = code.ToString(),
ErrorCode = code.ToString(),
Detail = detail,
StatusCode = Status(code)
};
/// <summary>Creates a KeyLoad exception with the status assigned to its error code.</summary>
/// <param name="code">Identifies the domain error code.</param>
/// <param name="detail">Provides safe caller-visible error detail.</param>
/// <returns>A KeyLoad exception with the matching HTTP status.</returns>
public static KeyLoadException Fail(ErrorCode code, string detail) => new(code, detail, Status(code));
/// <summary>Creates a safe typed failure while retaining the complete original cause.</summary>
/// <param name="code">Identifies the domain error.</param>
/// <param name="detail">Provides safe caller-visible detail.</param>
/// <param name="cause">Retains the original settled operation failure.</param>
/// <returns>The typed failure with its original cause.</returns>
public static KeyLoadException Fail(ErrorCode code, string detail, Exception cause)
{
ArgumentNullException.ThrowIfNull(cause);
return new(code, detail, Status(code), cause);
}
}