Skip to main content

api_validator/
api_validator.rs

1//! Example: using duck-diagnostic for REST API request/response validation.
2
3use duck_diagnostic::*;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6enum ApiError {
7  MissingField,
8  InvalidType,
9  ValueOutOfRange,
10  InvalidFormat,
11  AuthenticationFailed,
12  // warnings
13  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}