api_validator/
api_validator.rs1use duck_diagnostic::*;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6enum ApiError {
7 MissingField,
8 InvalidType,
9 ValueOutOfRange,
10 InvalidFormat,
11 AuthenticationFailed,
12 DeprecatedEndpoint,
14 SlowQuery,
15}
16
17impl DiagnosticCode for ApiError {
18 fn code(&self) -> &str {
19 match self {
20 Self::MissingField => "API001",
21 Self::InvalidType => "API002",
22 Self::ValueOutOfRange => "API003",
23 Self::InvalidFormat => "API004",
24 Self::AuthenticationFailed => "API005",
25 Self::DeprecatedEndpoint => "API-W01",
26 Self::SlowQuery => "API-W02",
27 }
28 }
29
30 fn severity(&self) -> Severity {
31 match self {
32 Self::DeprecatedEndpoint | Self::SlowQuery => Severity::Warning,
33 _ => Severity::Error,
34 }
35 }
36}
37
38fn main() {
39 let request_body = r#"{
40 "name": "Alice",
41 "age": -5,
42 "email": "not-an-email",
43 "role": "superadmin"
44}"#;
45
46 let mut engine = DiagnosticEngine::<ApiError>::new();
47
48 engine.emit(
49 Diagnostic::new(ApiError::ValueOutOfRange, "`age` must be a positive integer")
50 .with_label(Label::primary(
51 Span::new("POST /users", 3, 9, 2),
52 Some("negative values not allowed".into()),
53 ))
54 .with_help("age must be between 0 and 150"),
55 );
56
57 engine.emit(
58 Diagnostic::new(ApiError::InvalidFormat, "`email` is not a valid email address")
59 .with_label(Label::primary(
60 Span::new("POST /users", 4, 11, 14),
61 Some("missing @ symbol".into()),
62 ))
63 .with_help("expected format: user@domain.com"),
64 );
65
66 engine.emit(
67 Diagnostic::new(ApiError::DeprecatedEndpoint, "POST /users is deprecated, use POST /v2/users")
68 .with_label(Label::primary(Span::new("request", 1, 0, 1), None))
69 .with_note("this endpoint will be removed in v3"),
70 );
71
72 engine.print_all(request_body);
73}