1use crate::service::AwsServiceError;
6use http::StatusCode;
7
8pub 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
30pub 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
51pub 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
69pub 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
81pub 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
94pub 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
107pub fn validate_optional_json_range(
113 field: &str,
114 value: &serde_json::Value,
115 min: i64,
116 max: i64,
117) -> Result<(), AwsServiceError> {
118 if value.is_null() {
119 return Ok(());
120 }
121 let n = value.as_i64().ok_or_else(|| {
122 AwsServiceError::aws_error(
123 StatusCode::BAD_REQUEST,
124 "ValidationException",
125 format!(
126 "Value at '{}' failed to satisfy constraint: \
127 Member must have value between {} and {}",
128 field, min, max,
129 ),
130 )
131 })?;
132 validate_range_i64(field, n, min, max)
133}
134
135pub fn parse_optional_i64_param(
141 field: &str,
142 value: Option<&str>,
143) -> Result<Option<i64>, AwsServiceError> {
144 match value {
145 None => Ok(None),
146 Some(s) => {
147 let n = s.parse::<i64>().map_err(|_| {
148 AwsServiceError::aws_error(
149 StatusCode::BAD_REQUEST,
150 "ValidationException",
151 format!(
152 "Value '{}' at '{}' failed to satisfy constraint: \
153 Member must be a number",
154 s, field,
155 ),
156 )
157 })?;
158 Ok(Some(n))
159 }
160 }
161}
162
163pub fn validate_optional_enum(
165 field: &str,
166 value: Option<&str>,
167 allowed: &[&str],
168) -> Result<(), AwsServiceError> {
169 if let Some(v) = value {
170 validate_enum(field, v, allowed)?;
171 }
172 Ok(())
173}
174
175pub fn validate_optional_enum_value(
180 field: &str,
181 value: &serde_json::Value,
182 allowed: &[&str],
183) -> Result<(), AwsServiceError> {
184 if value.is_null() {
185 return Ok(());
186 }
187 let s = value.as_str().ok_or_else(|| {
188 AwsServiceError::aws_error(
189 StatusCode::BAD_REQUEST,
190 "SerializationException",
191 format!("Value for '{}' must be a string", field),
192 )
193 })?;
194 validate_enum(field, s, allowed)
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200
201 #[test]
202 fn validate_optional_json_range_rejects_non_integer() {
203 let val = serde_json::json!("abc");
204 let result = validate_optional_json_range("limit", &val, 1, 100);
205 assert!(result.is_err());
206 }
207
208 #[test]
209 fn validate_optional_json_range_rejects_large_unsigned() {
210 let val = serde_json::json!(u64::MAX);
211 let result = validate_optional_json_range("limit", &val, 1, 1000);
212 assert!(result.is_err());
213 }
214
215 #[test]
216 fn validate_optional_json_range_allows_null() {
217 let val = serde_json::Value::Null;
218 let result = validate_optional_json_range("limit", &val, 1, 100);
219 assert!(result.is_ok());
220 }
221
222 #[test]
223 fn validate_optional_json_range_validates_range() {
224 let val = serde_json::json!(0);
225 let result = validate_optional_json_range("limit", &val, 1, 100);
226 assert!(result.is_err());
227
228 let val = serde_json::json!(50);
229 let result = validate_optional_json_range("limit", &val, 1, 100);
230 assert!(result.is_ok());
231 }
232
233 #[test]
234 fn parse_optional_i64_param_rejects_non_numeric() {
235 let result = parse_optional_i64_param("maxItems", Some("abc"));
236 assert!(result.is_err());
237 }
238
239 #[test]
240 fn parse_optional_i64_param_allows_none() {
241 let result = parse_optional_i64_param("maxItems", None);
242 assert!(result.is_ok());
243 assert_eq!(result.unwrap(), None);
244 }
245
246 #[test]
247 fn parse_optional_i64_param_parses_valid_number() {
248 let result = parse_optional_i64_param("maxItems", Some("42"));
249 assert!(result.is_ok());
250 assert_eq!(result.unwrap(), Some(42));
251 }
252}