1pub mod body;
40pub mod cookie;
41pub mod cookie_named;
42pub(crate) mod cookie_util;
43pub mod extract;
44pub mod form;
45pub mod has_inner;
46pub mod header;
47pub mod header_named;
48pub mod json;
49#[cfg(feature = "multipart")]
50pub mod multipart;
51pub mod path;
52pub mod query;
53pub mod validation;
54
55use reinhardt_http::Error as CoreError;
56use std::any::TypeId;
57use std::collections::HashMap;
58use thiserror::Error;
59
60pub use reinhardt_core::exception::{ParamErrorContext, ParamType};
62pub use reinhardt_http::Request;
63
64use reinhardt_core::exception::param_error::{
66 extract_field_from_serde_error, extract_field_from_urlencoded_error,
67};
68
69pub use body::Body;
70pub use cookie::{Cookie, CookieStruct};
71pub use cookie_named::{CookieName, CookieNamed, CsrfToken, SessionId};
72pub use extract::FromRequest;
73pub use form::Form;
74pub use has_inner::HasInner;
75pub use header::{Header, HeaderStruct};
76pub use header_named::{Authorization, ContentType, HeaderName, HeaderNamed};
77pub use json::Json;
78#[cfg(feature = "multipart")]
79pub use multipart::Multipart;
80pub use path::{Path, PathStruct};
81pub use query::Query;
82#[cfg(feature = "validation")]
83pub use validation::Validated;
84pub use validation::{
85 ValidatedForm, ValidatedPath, ValidatedQuery, ValidationConstraints, WithValidation,
86};
87
88#[derive(Debug, Error)]
92#[non_exhaustive]
93pub enum ParamError {
94 #[error("Missing required parameter: {0}")]
96 MissingParameter(String),
97
98 #[error("{}", .0.format_error())]
100 InvalidParameter(Box<ParamErrorContext>),
101
102 #[error("{}", .0.format_error())]
104 ParseError(Box<ParamErrorContext>),
105
106 #[error("{}", .0.format_error())]
108 DeserializationError(Box<ParamErrorContext>),
109
110 #[error("{}", .0.format_error())]
112 UrlEncodingError(Box<ParamErrorContext>),
113
114 #[error("Request body error: {0}")]
116 BodyError(String),
117
118 #[error("Payload too large: {0}")]
120 PayloadTooLarge(String),
121
122 #[cfg(feature = "validation")]
124 #[error("{}", .0.format_error())]
125 ValidationError(Box<ParamErrorContext>),
126
127 #[cfg(feature = "validation")]
134 #[error("Validation failed: {0:?}")]
135 ValidationFailed(Box<reinhardt_core::validators::ValidationErrors>),
136}
137
138impl ParamError {
139 pub fn json_deserialization<T>(err: serde_json::Error, raw_value: Option<String>) -> Self {
141 let field_name = extract_field_from_serde_error(&err);
142 let mut ctx = ParamErrorContext::new(ParamType::Json, err.to_string())
143 .with_expected_type::<T>()
144 .with_source(Box::new(err));
145
146 if let Some(field) = field_name {
147 ctx = ctx.with_field(field);
148 }
149
150 if let Some(raw) = raw_value {
151 ctx = ctx.with_raw_value(raw);
152 }
153
154 ParamError::DeserializationError(Box::new(ctx))
155 }
156
157 pub fn url_encoding<T>(
159 param_type: ParamType,
160 err: serde_urlencoded::de::Error,
161 raw_value: Option<String>,
162 ) -> Self {
163 let field_name = extract_field_from_urlencoded_error(&err);
164 let mut ctx = ParamErrorContext::new(param_type, err.to_string())
165 .with_expected_type::<T>()
166 .with_source(Box::new(err));
167
168 if let Some(field) = field_name {
169 ctx = ctx.with_field(field);
170 }
171
172 if let Some(raw) = raw_value {
173 ctx = ctx.with_raw_value(raw);
174 }
175
176 ParamError::UrlEncodingError(Box::new(ctx))
177 }
178
179 pub fn invalid<T>(param_type: ParamType, message: impl Into<String>) -> Self {
181 let ctx = ParamErrorContext::new(param_type, message).with_expected_type::<T>();
182 ParamError::InvalidParameter(Box::new(ctx))
183 }
184
185 pub fn parse<T>(
187 param_type: ParamType,
188 message: impl Into<String>,
189 source: Box<dyn std::error::Error + Send + Sync>,
190 ) -> Self {
191 let ctx = ParamErrorContext::new(param_type, message)
192 .with_expected_type::<T>()
193 .with_source(source);
194 ParamError::ParseError(Box::new(ctx))
195 }
196
197 pub fn context(&self) -> Option<&ParamErrorContext> {
199 match self {
200 ParamError::InvalidParameter(ctx) => Some(ctx),
201 ParamError::ParseError(ctx) => Some(ctx),
202 ParamError::DeserializationError(ctx) => Some(ctx),
203 ParamError::UrlEncodingError(ctx) => Some(ctx),
204 #[cfg(feature = "validation")]
205 ParamError::ValidationError(ctx) => Some(ctx),
206 _ => None,
207 }
208 }
209
210 pub fn format_multiline(&self, include_raw_value: bool) -> String {
212 match self.context() {
213 Some(ctx) => ctx.format_multiline(include_raw_value),
214 None => format!(" {}", self),
215 }
216 }
217}
218
219impl From<ParamError> for CoreError {
220 fn from(err: ParamError) -> Self {
221 match err.context() {
223 Some(ctx) => CoreError::ParamValidation(Box::new(ctx.clone())),
224 None => CoreError::Validation(err.to_string()),
225 }
226 }
227}
228
229pub type ParamResult<T> = std::result::Result<T, ParamError>;
231
232pub struct ParamContext {
234 pub path_params: reinhardt_http::PathParams,
240 header_names: HashMap<TypeId, &'static str>,
242 cookie_names: HashMap<TypeId, &'static str>,
244}
245
246impl ParamContext {
247 pub fn new() -> Self {
258 Self {
259 path_params: reinhardt_http::PathParams::new(),
260 header_names: HashMap::new(),
261 cookie_names: HashMap::new(),
262 }
263 }
264 pub fn with_path_params(path_params: impl Into<reinhardt_http::PathParams>) -> Self {
287 Self {
288 path_params: path_params.into(),
289 header_names: HashMap::new(),
290 cookie_names: HashMap::new(),
291 }
292 }
293 pub fn get_path_param(&self, name: &str) -> Option<&str> {
311 self.path_params.get(name).map(|s| s.as_str())
312 }
313
314 pub fn set_header_name<T: 'static>(&mut self, name: &'static str) {
316 self.header_names.insert(TypeId::of::<T>(), name);
317 }
318
319 pub fn get_header_name<T: 'static>(&self) -> Option<&'static str> {
321 self.header_names.get(&TypeId::of::<T>()).copied()
322 }
323
324 pub fn set_cookie_name<T: 'static>(&mut self, name: &'static str) {
326 self.cookie_names.insert(TypeId::of::<T>(), name);
327 }
328
329 pub fn get_cookie_name<T: 'static>(&self) -> Option<&'static str> {
331 self.cookie_names.get(&TypeId::of::<T>()).copied()
332 }
333}
334
335impl Default for ParamContext {
336 fn default() -> Self {
337 Self::new()
338 }
339}