http_endpoint_server_harness/entities/
handler.rs1use super::{Request, Response};
2use std::sync::Arc;
3
4pub type HandlerFn = Arc<dyn Fn(&Request) -> Response + Send + Sync>;
6
7#[derive(Clone)]
9pub enum Handler {
10 Static(Response),
12 Dynamic(HandlerFn),
14}
15
16impl std::fmt::Debug for Handler {
17 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 match self {
19 Handler::Static(response) => f.debug_tuple("Static").field(response).finish(),
20 Handler::Dynamic(_) => f.debug_tuple("Dynamic").field(&"<fn>").finish(),
21 }
22 }
23}
24
25impl Handler {
26 pub fn new(response: Response) -> Self {
28 Handler::Static(response)
29 }
30
31 pub fn dynamic<F>(f: F) -> Self
33 where
34 F: Fn(&Request) -> Response + Send + Sync + 'static,
35 {
36 Handler::Dynamic(Arc::new(f))
37 }
38
39 pub fn from_json<T: serde::Serialize>(value: &T) -> Self {
41 Handler::Static(Response::ok().with_json(value))
42 }
43
44 pub fn with_status(self, status: u16) -> Self {
46 match self {
47 Handler::Static(mut response) => {
48 response.status = status;
49 Handler::Static(response)
50 }
51 Handler::Dynamic(_) => self, }
53 }
54
55 pub fn with_header(self, key: impl Into<String>, value: impl Into<String>) -> Self {
57 match self {
58 Handler::Static(response) => Handler::Static(response.with_header(key, value)),
59 Handler::Dynamic(_) => self, }
61 }
62
63 pub fn respond(&self, request: &Request) -> Response {
65 match self {
66 Handler::Static(response) => response.clone(),
67 Handler::Dynamic(f) => f(request),
68 }
69 }
70
71 pub fn response(&self) -> Response {
74 match self {
75 Handler::Static(response) => response.clone(),
76 Handler::Dynamic(_) => Response::new(200),
77 }
78 }
79}
80
81impl From<Response> for Handler {
82 fn from(response: Response) -> Self {
83 Handler::Static(response)
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90 use crate::entities::Method;
91 use std::collections::HashMap;
92
93 fn create_test_request(method: Method, path: &str, body: &[u8]) -> Request {
94 Request {
95 method,
96 path: path.to_string(),
97 headers: HashMap::new(),
98 body: body.to_vec(),
99 }
100 }
101
102 #[test]
103 fn test_handler_new() {
104 let response = Response::new(200);
105 let handler = Handler::new(response.clone());
106 assert!(matches!(handler, Handler::Static(_)));
107 }
108
109 #[test]
110 fn test_handler_from_json() {
111 let handler = Handler::from_json(&serde_json::json!({"test": true}));
112 let req = create_test_request(Method::Get, "/", &[]);
113 let response = handler.respond(&req);
114 assert_eq!(response.status, 200);
115 assert!(response.headers.get("content-type").unwrap().contains("application/json"));
116 }
117
118 #[test]
119 fn test_handler_with_status() {
120 let handler = Handler::from_json(&serde_json::json!({})).with_status(201);
121 let req = create_test_request(Method::Get, "/", &[]);
122 assert_eq!(handler.respond(&req).status, 201);
123 }
124
125 #[test]
126 fn test_handler_from_response() {
127 let response = Response::new(404);
128 let handler: Handler = response.into();
129 let req = create_test_request(Method::Get, "/", &[]);
130 assert_eq!(handler.respond(&req).status, 404);
131 }
132
133 #[test]
134 fn test_dynamic_handler() {
135 let handler = Handler::dynamic(|req: &Request| {
136 let body = format!("You requested: {}", req.path);
137 Response::new(200).with_body(body)
138 });
139
140 let req = create_test_request(Method::Get, "/api/users", &[]);
141 let response = handler.respond(&req);
142 assert_eq!(response.status, 200);
143 assert!(String::from_utf8_lossy(&response.body).contains("/api/users"));
144 }
145
146 #[test]
147 fn test_dynamic_handler_with_body() {
148 let handler = Handler::dynamic(|req: &Request| {
149 if let Some(body_str) = req.body_as_str() {
150 if let Ok(json) = serde_json::from_str::<serde_json::Value>(body_str) {
151 if let Some(name) = json.get("name").and_then(|v| v.as_str()) {
152 return Response::new(200).with_json(&serde_json::json!({
153 "message": format!("Hello, {}!", name)
154 }));
155 }
156 }
157 }
158 Response::new(400).with_body("Invalid request")
159 });
160
161 let req = create_test_request(Method::Post, "/greet", b"{\"name\": \"World\"}");
162 let response = handler.respond(&req);
163 assert_eq!(response.status, 200);
164 assert!(String::from_utf8_lossy(&response.body).contains("Hello, World!"));
165 }
166
167 #[test]
168 fn test_dynamic_handler_based_on_method() {
169 let handler = Handler::dynamic(|req: &Request| {
170 match req.method {
171 Method::Get => Response::new(200).with_body("GET response"),
172 Method::Post => Response::new(201).with_body("POST response"),
173 _ => Response::new(405).with_body("Method not allowed"),
174 }
175 });
176
177 let get_req = create_test_request(Method::Get, "/", &[]);
178 assert_eq!(handler.respond(&get_req).status, 200);
179
180 let post_req = create_test_request(Method::Post, "/", &[]);
181 assert_eq!(handler.respond(&post_req).status, 201);
182
183 let delete_req = create_test_request(Method::Delete, "/", &[]);
184 assert_eq!(handler.respond(&delete_req).status, 405);
185 }
186}
187