use axum::{
middleware,
routing::{delete, get, patch, post},
Router,
};
use crate::{
auth::{optional_auth, require_auth, AuthState},
auth_handlers::{generate_api_key, login, logout, me, refresh_token, AuthHandlerState},
graphql::{build_schema, graphql_handler, graphql_playground},
handlers::{
delete_asset, get_asset, get_dependencies, get_dependents, health_check, list_assets,
metrics, register_asset, update_asset, version_info, AppState,
},
};
pub fn build_router(state: AppState) -> Router {
Router::new()
.route("/health", get(health_check))
.route("/metrics", get(metrics))
.route("/version", get(version_info))
.nest("/v1", build_v1_routes())
.with_state(state)
}
pub fn build_router_with_auth(
state: AppState,
auth_handler_state: AuthHandlerState,
auth_state: AuthState,
) -> Router {
let public_routes = Router::new()
.route("/health", get(health_check))
.route("/metrics", get(metrics))
.route("/version", get(version_info))
.with_state(state.clone());
let auth_routes = Router::new()
.route("/login", post(login))
.route("/refresh", post(refresh_token))
.with_state(auth_handler_state.clone());
let protected_auth_routes = Router::new()
.route("/me", get(me))
.route("/logout", post(logout))
.route("/api-keys", post(generate_api_key))
.layer(middleware::from_fn_with_state(
auth_state.clone(),
require_auth,
))
.with_state(auth_handler_state);
let v1_routes = build_v1_routes().with_state(state);
Router::new()
.merge(public_routes)
.nest("/v1/auth", auth_routes)
.nest("/v1/auth", protected_auth_routes)
.nest("/v1", v1_routes)
}
pub fn build_router_with_graphql(
state: AppState,
auth_handler_state: AuthHandlerState,
auth_state: AuthState,
) -> Router {
let schema = build_schema(state.services.clone());
let public_routes = Router::new()
.route("/health", get(health_check))
.route("/metrics", get(metrics))
.route("/version", get(version_info))
.route("/graphql/playground", get(graphql_playground))
.with_state(state.clone());
let graphql_route = Router::new()
.route("/graphql", post(graphql_handler))
.layer(middleware::from_fn_with_state(
auth_state.clone(),
optional_auth,
))
.with_state(schema);
let auth_routes = Router::new()
.route("/login", post(login))
.route("/refresh", post(refresh_token))
.with_state(auth_handler_state.clone());
let protected_auth_routes = Router::new()
.route("/me", get(me))
.route("/logout", post(logout))
.route("/api-keys", post(generate_api_key))
.layer(middleware::from_fn_with_state(
auth_state.clone(),
require_auth,
))
.with_state(auth_handler_state);
let v1_routes = build_v1_routes().with_state(state);
Router::new()
.merge(public_routes)
.merge(graphql_route)
.nest("/v1/auth", auth_routes)
.nest("/v1/auth", protected_auth_routes)
.nest("/v1", v1_routes)
}
fn build_v1_routes() -> Router<AppState> {
Router::new()
.route("/assets", post(register_asset))
.route("/assets", get(list_assets))
.route("/assets/:id", get(get_asset))
.route("/assets/:id", patch(update_asset))
.route("/assets/:id", delete(delete_asset))
.route("/assets/:id/dependencies", get(get_dependencies))
.route("/assets/:id/dependents", get(get_dependents))
}
#[derive(Debug, Clone)]
pub struct RouteConfig {
pub base_path: String,
pub version: String,
}
impl Default for RouteConfig {
fn default() -> Self {
Self {
base_path: "/".to_string(),
version: "v1".to_string(),
}
}
}
impl RouteConfig {
pub fn new() -> Self {
Self::default()
}
pub fn with_base_path(mut self, path: impl Into<String>) -> Self {
self.base_path = path.into();
self
}
pub fn with_version(mut self, version: impl Into<String>) -> Self {
self.version = version.into();
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_route_config_default() {
let config = RouteConfig::default();
assert_eq!(config.base_path, "/");
assert_eq!(config.version, "v1");
}
#[test]
fn test_route_config_builder() {
let config = RouteConfig::new()
.with_base_path("/api")
.with_version("v2");
assert_eq!(config.base_path, "/api");
assert_eq!(config.version, "v2");
}
}