Skip to main content

fakecloud_core/
validation.rs

1//! Generic input validation helpers for AWS-compatible error responses.
2//!
3//! All validators return `AwsServiceError` with `ValidationException` and 400 status.
4
5use crate::service::AwsServiceError;
6use http::StatusCode;
7
8/// Validate a string's length is within [min, max].
9pub fn validate_string_length(
10    field: &str,
11    value: &str,
12    min: usize,
13    max: usize,
14) -> Result<(), AwsServiceError> {
15    let len = value.len();
16    if len < min || len > max {
17        return Err(AwsServiceError::aws_error(
18            StatusCode::BAD_REQUEST,
19            "ValidationException",
20            format!(
21                "Value at '{}' failed to satisfy constraint: \
22                 Member must have length between {} and {}",
23                field, min, max,
24            ),
25        ));
26    }
27    Ok(())
28}
29
30/// Validate an integer is within [min, max].
31pub fn validate_range_i64(
32    field: &str,
33    value: i64,
34    min: i64,
35    max: i64,
36) -> Result<(), AwsServiceError> {
37    if value < min || value > max {
38        return Err(AwsServiceError::aws_error(
39            StatusCode::BAD_REQUEST,
40            "ValidationException",
41            format!(
42                "Value '{}' at '{}' failed to satisfy constraint: \
43                 Member must have value between {} and {}",
44                value, field, min, max,
45            ),
46        ));
47    }
48    Ok(())
49}
50
51/// Validate a string is one of the allowed enum values.
52pub fn validate_enum(field: &str, value: &str, allowed: &[&str]) -> Result<(), AwsServiceError> {
53    if !allowed.contains(&value) {
54        return Err(AwsServiceError::aws_error(
55            StatusCode::BAD_REQUEST,
56            "ValidationException",
57            format!(
58                "Value '{}' at '{}' failed to satisfy constraint: \
59                 Member must satisfy enum value set: [{}]",
60                value,
61                field,
62                allowed.join(", "),
63            ),
64        ));
65    }
66    Ok(())
67}
68
69/// Validate that a required field is present (not null/missing).
70pub fn validate_required(field: &str, value: &serde_json::Value) -> Result<(), AwsServiceError> {
71    if value.is_null() {
72        return Err(AwsServiceError::aws_error(
73            StatusCode::BAD_REQUEST,
74            "ValidationException",
75            format!("{} is required", field),
76        ));
77    }
78    Ok(())
79}
80
81/// Validate an optional string's length if present.
82pub fn validate_optional_string_length(
83    field: &str,
84    value: Option<&str>,
85    min: usize,
86    max: usize,
87) -> Result<(), AwsServiceError> {
88    if let Some(v) = value {
89        validate_string_length(field, v, min, max)?;
90    }
91    Ok(())
92}
93
94/// Validate an optional integer range if present.
95pub fn validate_optional_range_i64(
96    field: &str,
97    value: Option<i64>,
98    min: i64,
99    max: i64,
100) -> Result<(), AwsServiceError> {
101    if let Some(v) = value {
102        validate_range_i64(field, v, min, max)?;
103    }
104    Ok(())
105}
106
107/// Validate an optional enum value if present.
108pub fn validate_optional_enum(
109    field: &str,
110    value: Option<&str>,
111    allowed: &[&str],
112) -> Result<(), AwsServiceError> {
113    if let Some(v) = value {
114        validate_enum(field, v, allowed)?;
115    }
116    Ok(())
117}
118
119/// Validate an optional enum from a JSON value, rejecting non-string types.
120///
121/// Unlike [`validate_optional_enum`], this takes a raw [`serde_json::Value`] so it can
122/// distinguish between a missing/null field (ok to skip) and a non-string value (error).
123pub fn validate_optional_enum_value(
124    field: &str,
125    value: &serde_json::Value,
126    allowed: &[&str],
127) -> Result<(), AwsServiceError> {
128    if value.is_null() {
129        return Ok(());
130    }
131    let s = value.as_str().ok_or_else(|| {
132        AwsServiceError::aws_error(
133            StatusCode::BAD_REQUEST,
134            "SerializationException",
135            format!("Value for '{}' must be a string", field),
136        )
137    })?;
138    validate_enum(field, s, allowed)
139}