llm-shield-api 0.1.0

Production-grade REST API for LLM Shield
//! Route configuration

use axum::{routing::{get, post}, Router};

use crate::handlers;
use crate::state::AppState;

/// Create the application router
///
/// ## Routes
/// - GET /health - Basic health check
/// - GET /health/ready - Readiness probe
/// - GET /health/live - Liveness probe
/// - GET /version - Version information
/// - POST /v1/scan/prompt - Scan user prompt
pub fn create_router() -> Router {
    Router::new()
        .route("/health", get(handlers::health))
        .route("/health/ready", get(handlers::ready))
        .route("/health/live", get(handlers::live))
        .route("/version", get(handlers::version))
}

/// Create the application router with state
pub fn create_router_with_state(state: AppState) -> Router {
    Router::new()
        .route("/health", get(handlers::health))
        .route("/health/ready", get(handlers::ready))
        .route("/health/live", get(handlers::live))
        .route("/version", get(handlers::version))
        .route("/v1/scan/prompt", post(handlers::scan_prompt))
        .route("/v1/scan/output", post(handlers::scan_output))
        .route("/v1/scan/batch", post(handlers::scan_batch))
        .route("/v1/scanners", get(handlers::list_scanners))
        .with_state(state)
}

#[cfg(test)]
mod tests {
    use super::*;
    use axum::body::Body;
    use axum::http::{Request, StatusCode};
    use tower::ServiceExt; // For `oneshot`

    #[tokio::test]
    async fn test_health_route() {
        let app = create_router();

        let response = app
            .oneshot(Request::builder().uri("/health").body(Body::empty()).unwrap())
            .await
            .unwrap();

        assert_eq!(response.status(), StatusCode::OK);
    }

    #[tokio::test]
    async fn test_ready_route() {
        let app = create_router();

        let response = app
            .oneshot(
                Request::builder()
                    .uri("/health/ready")
                    .body(Body::empty())
                    .unwrap(),
            )
            .await
            .unwrap();

        assert_eq!(response.status(), StatusCode::OK);
    }

    #[tokio::test]
    async fn test_live_route() {
        let app = create_router();

        let response = app
            .oneshot(
                Request::builder()
                    .uri("/health/live")
                    .body(Body::empty())
                    .unwrap(),
            )
            .await
            .unwrap();

        assert_eq!(response.status(), StatusCode::OK);
    }

    #[tokio::test]
    async fn test_version_route() {
        let app = create_router();

        let response = app
            .oneshot(
                Request::builder()
                    .uri("/version")
                    .body(Body::empty())
                    .unwrap(),
            )
            .await
            .unwrap();

        assert_eq!(response.status(), StatusCode::OK);
    }

    #[tokio::test]
    async fn test_not_found() {
        let app = create_router();

        let response = app
            .oneshot(
                Request::builder()
                    .uri("/notfound")
                    .body(Body::empty())
                    .unwrap(),
            )
            .await
            .unwrap();

        assert_eq!(response.status(), StatusCode::NOT_FOUND);
    }
}