allframe_core/router/
builder.rs

1//! Route builder for fluent route configuration
2//!
3//! This module provides a builder pattern for configuring routes with
4//! metadata, tags, descriptions, and other OpenAPI properties.
5
6use serde_json::Value;
7
8use crate::router::{Method, RouteMetadata};
9
10/// Builder for configuring a route with metadata
11///
12/// Provides a fluent interface for setting route properties
13/// like description, tags, request/response schemas, etc.
14pub struct RouteBuilder {
15    path: String,
16    method: Method,
17    metadata: RouteMetadata,
18}
19
20impl RouteBuilder {
21    /// Create a new route builder
22    pub fn new(path: impl Into<String>, method: Method) -> Self {
23        let path = path.into();
24        let metadata = RouteMetadata::new(&path, method, "rest");
25
26        Self {
27            path,
28            method,
29            metadata,
30        }
31    }
32
33    /// Set the route description
34    pub fn description(mut self, description: impl Into<String>) -> Self {
35        self.metadata = self.metadata.with_description(description);
36        self
37    }
38
39    /// Set the request schema
40    pub fn request_schema(mut self, schema: Value) -> Self {
41        self.metadata = self.metadata.with_request_schema(schema);
42        self
43    }
44
45    /// Set the response schema
46    pub fn response_schema(mut self, schema: Value) -> Self {
47        self.metadata = self.metadata.with_response_schema(schema);
48        self
49    }
50
51    /// Build the route metadata
52    pub fn build(self) -> RouteMetadata {
53        self.metadata
54    }
55
56    /// Get the path
57    pub fn path(&self) -> &str {
58        &self.path
59    }
60
61    /// Get the method
62    pub fn method(&self) -> Method {
63        self.method
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use serde_json::json;
70
71    use super::*;
72
73    #[test]
74    fn test_route_builder_basic() {
75        let builder = RouteBuilder::new("/users", Method::GET);
76        let metadata = builder.build();
77
78        assert_eq!(metadata.path, "/users");
79        assert_eq!(metadata.method, "GET");
80        assert_eq!(metadata.protocol, "rest");
81    }
82
83    #[test]
84    fn test_route_builder_with_description() {
85        let builder = RouteBuilder::new("/users", Method::GET).description("Get all users");
86        let metadata = builder.build();
87
88        assert_eq!(metadata.description, Some("Get all users".to_string()));
89    }
90
91    #[test]
92    fn test_route_builder_with_request_schema() {
93        let schema = json!({
94            "type": "object",
95            "properties": {
96                "name": {"type": "string"}
97            }
98        });
99
100        let builder = RouteBuilder::new("/users", Method::POST).request_schema(schema.clone());
101        let metadata = builder.build();
102
103        assert_eq!(metadata.request_schema, Some(schema));
104    }
105
106    #[test]
107    fn test_route_builder_with_response_schema() {
108        let schema = json!({
109            "type": "object",
110            "properties": {
111                "id": {"type": "string"}
112            }
113        });
114
115        let builder = RouteBuilder::new("/users", Method::GET).response_schema(schema.clone());
116        let metadata = builder.build();
117
118        assert_eq!(metadata.response_schema, Some(schema));
119    }
120
121    #[test]
122    fn test_route_builder_fluent_chain() {
123        let request = json!({"type": "object"});
124        let response = json!({"type": "array"});
125
126        let metadata = RouteBuilder::new("/users", Method::POST)
127            .description("Create a new user")
128            .request_schema(request.clone())
129            .response_schema(response.clone())
130            .build();
131
132        assert_eq!(metadata.path, "/users");
133        assert_eq!(metadata.method, "POST");
134        assert_eq!(metadata.description, Some("Create a new user".to_string()));
135        assert_eq!(metadata.request_schema, Some(request));
136        assert_eq!(metadata.response_schema, Some(response));
137    }
138
139    #[test]
140    fn test_route_builder_all_http_methods() {
141        let methods = vec![
142            Method::GET,
143            Method::POST,
144            Method::PUT,
145            Method::DELETE,
146            Method::PATCH,
147            Method::HEAD,
148            Method::OPTIONS,
149        ];
150
151        for method in methods {
152            let builder = RouteBuilder::new("/test", method);
153            assert_eq!(builder.method(), method);
154        }
155    }
156
157    #[test]
158    fn test_route_builder_path_accessor() {
159        let builder = RouteBuilder::new("/users/{id}", Method::GET);
160        assert_eq!(builder.path(), "/users/{id}");
161    }
162
163    #[test]
164    fn test_route_builder_method_accessor() {
165        let builder = RouteBuilder::new("/users", Method::POST);
166        assert_eq!(builder.method(), Method::POST);
167    }
168
169    #[test]
170    fn test_route_builder_multiple_routes() {
171        let route1 = RouteBuilder::new("/users", Method::GET)
172            .description("List users")
173            .build();
174
175        let route2 = RouteBuilder::new("/users", Method::POST)
176            .description("Create user")
177            .build();
178
179        assert_eq!(route1.path, "/users");
180        assert_eq!(route1.method, "GET");
181        assert_eq!(route2.path, "/users");
182        assert_eq!(route2.method, "POST");
183    }
184
185    #[test]
186    fn test_route_builder_minimal_configuration() {
187        let metadata = RouteBuilder::new("/health", Method::GET).build();
188
189        assert_eq!(metadata.path, "/health");
190        assert_eq!(metadata.method, "GET");
191        assert_eq!(metadata.description, None);
192        assert_eq!(metadata.request_schema, None);
193        assert_eq!(metadata.response_schema, None);
194    }
195}