1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
6pub enum Method {
7 Get,
8 Post,
9 Put,
10 Patch,
11 Delete,
12 Head,
13 Options,
14 Trace,
15}
16
17impl Method {
18 pub fn as_str(&self) -> &'static str {
19 match self {
20 Method::Get => "GET",
21 Method::Post => "POST",
22 Method::Put => "PUT",
23 Method::Patch => "PATCH",
24 Method::Delete => "DELETE",
25 Method::Head => "HEAD",
26 Method::Options => "OPTIONS",
27 Method::Trace => "TRACE",
28 }
29 }
30}
31
32impl std::fmt::Display for Method {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 write!(f, "{}", self.as_str())
35 }
36}
37
38impl std::str::FromStr for Method {
39 type Err = String;
40
41 fn from_str(s: &str) -> Result<Self, Self::Err> {
42 match s.to_uppercase().as_str() {
43 "GET" => Ok(Method::Get),
44 "POST" => Ok(Method::Post),
45 "PUT" => Ok(Method::Put),
46 "PATCH" => Ok(Method::Patch),
47 "DELETE" => Ok(Method::Delete),
48 "HEAD" => Ok(Method::Head),
49 "OPTIONS" => Ok(Method::Options),
50 "TRACE" => Ok(Method::Trace),
51 _ => Err(format!("Unknown HTTP method: {}", s)),
52 }
53 }
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct CorsConfig {
59 pub allowed_origins: Vec<String>,
60 pub allowed_methods: Vec<String>,
61 #[serde(default)]
62 pub allowed_headers: Vec<String>,
63 #[serde(skip_serializing_if = "Option::is_none")]
64 pub expose_headers: Option<Vec<String>>,
65 #[serde(skip_serializing_if = "Option::is_none")]
66 pub max_age: Option<u32>,
67 #[serde(skip_serializing_if = "Option::is_none")]
68 pub allow_credentials: Option<bool>,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct RouteMetadata {
74 pub method: String,
75 pub path: String,
76 pub handler_name: String,
77 pub request_schema: Option<Value>,
78 pub response_schema: Option<Value>,
79 pub parameter_schema: Option<Value>,
80 #[serde(skip_serializing_if = "Option::is_none")]
81 pub file_params: Option<Value>,
82 pub is_async: bool,
83 pub cors: Option<CorsConfig>,
84 #[serde(skip_serializing_if = "Option::is_none")]
86 pub body_param_name: Option<String>,
87 #[cfg(feature = "di")]
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub handler_dependencies: Option<Vec<String>>,
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct CompressionConfig {
96 #[serde(default = "default_true")]
98 pub gzip: bool,
99 #[serde(default = "default_true")]
101 pub brotli: bool,
102 #[serde(default = "default_compression_min_size")]
104 pub min_size: usize,
105 #[serde(default = "default_compression_quality")]
107 pub quality: u32,
108}
109
110const fn default_true() -> bool {
111 true
112}
113
114const fn default_compression_min_size() -> usize {
115 1024
116}
117
118const fn default_compression_quality() -> u32 {
119 6
120}
121
122impl Default for CompressionConfig {
123 fn default() -> Self {
124 Self {
125 gzip: true,
126 brotli: true,
127 min_size: default_compression_min_size(),
128 quality: default_compression_quality(),
129 }
130 }
131}
132
133#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct RateLimitConfig {
136 pub per_second: u64,
138 pub burst: u32,
140 #[serde(default = "default_true")]
142 pub ip_based: bool,
143}
144
145impl Default for RateLimitConfig {
146 fn default() -> Self {
147 Self {
148 per_second: 100,
149 burst: 200,
150 ip_based: true,
151 }
152 }
153}