mockforge_http/
token_response.rs1use axum::{
6 body::Body,
7 http::{Response, StatusCode},
8 response::IntoResponse,
9};
10use mockforge_data::rag::RagConfig;
11use mockforge_data::{resolve_tokens, resolve_tokens_with_rag};
12use serde_json::Value;
13use tracing::*;
14
15pub async fn resolve_response_tokens(body: Value) -> Result<Value, String> {
17 resolve_tokens(&body)
18 .await
19 .map_err(|e| format!("Failed to resolve tokens: {}", e))
20}
21
22pub async fn resolve_response_tokens_with_rag(
24 body: Value,
25 rag_config: RagConfig,
26) -> Result<Value, String> {
27 resolve_tokens_with_rag(&body, rag_config)
28 .await
29 .map_err(|e| format!("Failed to resolve tokens with RAG: {}", e))
30}
31
32pub async fn create_token_resolved_response(
34 status: StatusCode,
35 body: Value,
36 use_rag: bool,
37 rag_config: Option<RagConfig>,
38) -> Response<Body> {
39 let resolved_body = if use_rag {
40 let config = rag_config.unwrap_or_default();
41 match resolve_response_tokens_with_rag(body.clone(), config).await {
42 Ok(resolved) => resolved,
43 Err(e) => {
44 error!(error = %e, "Failed to resolve tokens with RAG, using original body");
45 body
46 }
47 }
48 } else {
49 match resolve_response_tokens(body.clone()).await {
50 Ok(resolved) => resolved,
51 Err(e) => {
52 error!(error = %e, "Failed to resolve tokens, using original body");
53 body
54 }
55 }
56 };
57
58 let json_string = match serde_json::to_string_pretty(&resolved_body) {
59 Ok(s) => s,
60 Err(e) => {
61 error!(error = %e, "Failed to serialize response");
62 return (StatusCode::INTERNAL_SERVER_ERROR, "Failed to serialize response")
63 .into_response();
64 }
65 };
66
67 Response::builder()
68 .status(status)
69 .header("Content-Type", "application/json")
70 .body(Body::from(json_string))
71 .unwrap_or_else(|e| {
72 error!(error = %e, "Failed to build response");
73 (StatusCode::INTERNAL_SERVER_ERROR, "Failed to build response").into_response()
74 })
75}
76
77pub struct TokenResolvedResponse {
79 status: StatusCode,
80 body: Value,
81 use_rag: bool,
82 rag_config: Option<RagConfig>,
83}
84
85impl TokenResolvedResponse {
86 pub fn new(status: StatusCode, body: Value) -> Self {
88 Self {
89 status,
90 body,
91 use_rag: false,
92 rag_config: None,
93 }
94 }
95
96 pub fn with_rag(mut self, config: RagConfig) -> Self {
98 self.use_rag = true;
99 self.rag_config = Some(config);
100 self
101 }
102
103 pub async fn build(self) -> Response<Body> {
105 create_token_resolved_response(self.status, self.body, self.use_rag, self.rag_config).await
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112 use serde_json::json;
113
114 #[tokio::test]
115 async fn test_resolve_response_tokens() {
116 let body = json!({
117 "id": "$random.uuid",
118 "name": "$faker.name",
119 "email": "$faker.email"
120 });
121
122 let result = resolve_response_tokens(body).await;
123 assert!(result.is_ok());
124
125 let resolved = result.unwrap();
126 assert!(resolved["id"].is_string());
127 assert!(resolved["name"].is_string());
128 assert!(resolved["email"].is_string());
129 }
130
131 #[tokio::test]
132 async fn test_resolve_nested_tokens() {
133 let body = json!({
134 "user": {
135 "id": "$random.uuid",
136 "profile": {
137 "name": "$faker.name",
138 "contact": {
139 "email": "$faker.email",
140 "phone": "$faker.phone"
141 }
142 }
143 }
144 });
145
146 let result = resolve_response_tokens(body).await;
147 assert!(result.is_ok());
148
149 let resolved = result.unwrap();
150 assert!(resolved["user"]["id"].is_string());
151 assert!(resolved["user"]["profile"]["name"].is_string());
152 assert!(resolved["user"]["profile"]["contact"]["email"].is_string());
153 }
154
155 #[tokio::test]
156 async fn test_resolve_array_tokens() {
157 let body = json!({
158 "users": [
159 {"id": "$random.uuid", "name": "$faker.name"},
160 {"id": "$random.uuid", "name": "$faker.name"}
161 ]
162 });
163
164 let result = resolve_response_tokens(body).await;
165 assert!(result.is_ok());
166
167 let resolved = result.unwrap();
168 let users = resolved["users"].as_array().unwrap();
169 assert_eq!(users.len(), 2);
170 assert!(users[0]["id"].is_string());
171 assert!(users[0]["name"].is_string());
172 }
173
174 #[tokio::test]
175 async fn test_token_resolved_response_builder() {
176 let body = json!({"message": "test"});
177 let response = TokenResolvedResponse::new(StatusCode::OK, body).build().await;
178
179 assert_eq!(response.status(), StatusCode::OK);
180 }
181}