From 92c784dcf17b6abb2c6ac8ee008f5d80fba4d9f8 Mon Sep 17 00:00:00 2001 From: continuist Date: Sat, 28 Jun 2025 00:29:50 -0400 Subject: [PATCH] Add a healthcheck route to backend --- backend/crates/api/Cargo.toml | 1 + backend/crates/api/src/lib.rs | 57 +++++++++++++++++++++++++++++++++++ docker-compose.yml | 5 --- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/backend/crates/api/Cargo.toml b/backend/crates/api/Cargo.toml index 93a78e0..242c3f3 100644 --- a/backend/crates/api/Cargo.toml +++ b/backend/crates/api/Cargo.toml @@ -17,6 +17,7 @@ tracing-subscriber = { workspace = true, features = ["env-filter"] } serde = { workspace = true } serde_json = "1.0" uuid = { workspace = true } +chrono = { workspace = true } [dev-dependencies] chrono = { workspace = true } diff --git a/backend/crates/api/src/lib.rs b/backend/crates/api/src/lib.rs index 794153a..3377a7d 100644 --- a/backend/crates/api/src/lib.rs +++ b/backend/crates/api/src/lib.rs @@ -15,6 +15,9 @@ //! //! ## API Endpoints //! +//! ### Health Check +//! - `GET /health` - Health check endpoint for monitoring +//! //! ### Users //! - `POST /users` - Create a new user //! - `GET /users/:id` - Get a user by ID @@ -156,6 +159,7 @@ where .allow_headers(Any); let app = Router::new() + .route("/health", get(health_check)) .route("/users", post(create_user::)) .route("/users/:id", get(get_user::)) .route("/users", get(list_users::)) @@ -255,6 +259,8 @@ where /// Deletes a user by ID. /// +/// Returns a 204 No Content response on successful deletion. +/// /// # Response /// - `204 No Content` - User successfully deleted /// - `404 Not Found` - User with specified ID not found @@ -351,6 +357,8 @@ where /// Deletes a product by ID. /// +/// Returns a 204 No Content response on successful deletion. +/// /// # Response /// - `204 No Content` - Product successfully deleted /// - `404 Not Found` - Product with specified ID not found @@ -367,6 +375,21 @@ where } } +/// Health check endpoint for monitoring and load balancers. +/// +/// Returns a simple JSON response indicating the service is healthy. +/// This endpoint is used by Docker healthchecks and monitoring systems. +/// +/// # Response +/// - `200 OK` - Service is healthy +async fn health_check() -> impl IntoResponse { + (StatusCode::OK, Json(serde_json::json!({ + "status": "healthy", + "service": "sharenet-api", + "timestamp": chrono::Utc::now().to_rfc3339() + }))) +} + #[cfg(test)] mod tests { //! # API Tests @@ -566,6 +589,7 @@ mod tests { }; Router::new() + .route("/health", get(health_check)) .route("/users", post(create_user::)) .route("/users/:id", get(get_user::)) .route("/users", get(list_users::)) @@ -946,6 +970,39 @@ mod tests { } } + mod health_check { + //! # Health Check Endpoint Tests + //! + //! Tests for the health check endpoint used by Docker healthchecks + //! and monitoring systems. + + use super::*; + + /// Tests the health check endpoint returns a healthy status. + #[tokio::test] + async fn test_health_check() { + let app = create_test_app(); + + let response = app + .oneshot( + Request::builder() + .method("GET") + .uri("/health") + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + + assert_eq!(response.status(), StatusCode::OK); + + let health_data: serde_json::Value = extract_json(response).await; + assert_eq!(health_data["status"], "healthy"); + assert_eq!(health_data["service"], "sharenet-api"); + assert!(health_data["timestamp"].is_string()); + } + } + mod product_endpoints { //! # Product Endpoint Tests //! diff --git a/docker-compose.yml b/docker-compose.yml index 4272fe0..4344c66 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -56,11 +56,6 @@ services: depends_on: backend: condition: service_healthy - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"] - interval: 30s - timeout: 10s - retries: 3 networks: - sharenet-network