1use axum::{
6 middleware,
7 routing::{delete, get, patch, post},
8 Router,
9};
10
11use crate::{
12 auth::{optional_auth, require_auth, AuthState},
13 auth_handlers::{generate_api_key, login, logout, me, refresh_token, AuthHandlerState},
14 graphql::{build_schema, graphql_handler, graphql_playground},
15 handlers::{
16 delete_asset, get_asset, get_dependencies, get_dependents, health_check, list_assets,
17 metrics, register_asset, update_asset, version_info, AppState,
18 },
19};
20
21pub fn build_router(state: AppState) -> Router {
23 Router::new()
24 .route("/health", get(health_check))
26 .route("/metrics", get(metrics))
27 .route("/version", get(version_info))
28 .nest("/v1", build_v1_routes())
30 .with_state(state)
31}
32
33pub fn build_router_with_auth(
38 state: AppState,
39 auth_handler_state: AuthHandlerState,
40 auth_state: AuthState,
41) -> Router {
42 let public_routes = Router::new()
44 .route("/health", get(health_check))
45 .route("/metrics", get(metrics))
46 .route("/version", get(version_info))
47 .with_state(state.clone());
48
49 let auth_routes = Router::new()
51 .route("/login", post(login))
52 .route("/refresh", post(refresh_token))
53 .with_state(auth_handler_state.clone());
54
55 let protected_auth_routes = Router::new()
57 .route("/me", get(me))
58 .route("/logout", post(logout))
59 .route("/api-keys", post(generate_api_key))
60 .layer(middleware::from_fn_with_state(
61 auth_state.clone(),
62 require_auth,
63 ))
64 .with_state(auth_handler_state);
65
66 let v1_routes = build_v1_routes().with_state(state);
68
69 Router::new()
71 .merge(public_routes)
72 .nest("/v1/auth", auth_routes)
73 .nest("/v1/auth", protected_auth_routes)
74 .nest("/v1", v1_routes)
75}
76
77pub fn build_router_with_graphql(
82 state: AppState,
83 auth_handler_state: AuthHandlerState,
84 auth_state: AuthState,
85) -> Router {
86 let schema = build_schema(state.services.clone());
88
89 let public_routes = Router::new()
91 .route("/health", get(health_check))
92 .route("/metrics", get(metrics))
93 .route("/version", get(version_info))
94 .route("/graphql/playground", get(graphql_playground))
95 .with_state(state.clone());
96
97 let graphql_route = Router::new()
99 .route("/graphql", post(graphql_handler))
100 .layer(middleware::from_fn_with_state(
101 auth_state.clone(),
102 optional_auth,
103 ))
104 .with_state(schema);
105
106 let auth_routes = Router::new()
108 .route("/login", post(login))
109 .route("/refresh", post(refresh_token))
110 .with_state(auth_handler_state.clone());
111
112 let protected_auth_routes = Router::new()
114 .route("/me", get(me))
115 .route("/logout", post(logout))
116 .route("/api-keys", post(generate_api_key))
117 .layer(middleware::from_fn_with_state(
118 auth_state.clone(),
119 require_auth,
120 ))
121 .with_state(auth_handler_state);
122
123 let v1_routes = build_v1_routes().with_state(state);
125
126 Router::new()
128 .merge(public_routes)
129 .merge(graphql_route)
130 .nest("/v1/auth", auth_routes)
131 .nest("/v1/auth", protected_auth_routes)
132 .nest("/v1", v1_routes)
133}
134
135fn build_v1_routes() -> Router<AppState> {
137 Router::new()
138 .route("/assets", post(register_asset))
140 .route("/assets", get(list_assets))
141 .route("/assets/:id", get(get_asset))
142 .route("/assets/:id", patch(update_asset))
143 .route("/assets/:id", delete(delete_asset))
144 .route("/assets/:id/dependencies", get(get_dependencies))
146 .route("/assets/:id/dependents", get(get_dependents))
147}
148
149#[derive(Debug, Clone)]
151pub struct RouteConfig {
152 pub base_path: String,
154
155 pub version: String,
157}
158
159impl Default for RouteConfig {
160 fn default() -> Self {
161 Self {
162 base_path: "/".to_string(),
163 version: "v1".to_string(),
164 }
165 }
166}
167
168impl RouteConfig {
169 pub fn new() -> Self {
171 Self::default()
172 }
173
174 pub fn with_base_path(mut self, path: impl Into<String>) -> Self {
176 self.base_path = path.into();
177 self
178 }
179
180 pub fn with_version(mut self, version: impl Into<String>) -> Self {
182 self.version = version.into();
183 self
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190
191 #[test]
192 fn test_route_config_default() {
193 let config = RouteConfig::default();
194 assert_eq!(config.base_path, "/");
195 assert_eq!(config.version, "v1");
196 }
197
198 #[test]
199 fn test_route_config_builder() {
200 let config = RouteConfig::new()
201 .with_base_path("/api")
202 .with_version("v2");
203
204 assert_eq!(config.base_path, "/api");
205 assert_eq!(config.version, "v2");
206 }
207}