using System.Reflection; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; using StartupHelpers; using Swashbuckle.AspNetCore.Annotations; namespace Api.Controllers { /// /// Controller that exposes simple health and readiness endpoints for the API. /// Routes are prefixed with "api/health". /// [ApiController] [Route("api/[controller]")] // Enables only the "FrontendOnly" CORS policy so browser requests from the frontend are allowed. [EnableCors("FrontendOnly")] public sealed class HealthController : ControllerBase { /// /// Returns the deployed API version baked into the assembly at build time. /// The version format is 1.0.0-build.{yyyyMMddHHmmss} as defined in api.csproj. /// Used by the web frontend to display the running build in the page footer. /// /// 200 OK with JSON payload: { "version": "1.0.0-build.20250522103045" }. // GET api/health/version [HttpGet("version")] [SwaggerOperation(Summary = "API version", Description = "Returns the deployed API assembly version.")] [SwaggerResponse(StatusCodes.Status200OK, "Version returned")] [ProducesResponseType(StatusCodes.Status200OK)] public IActionResult Version() => Ok(new { version = StartupExtensions.GetApplicationVersion(Assembly.GetExecutingAssembly()) }); /// /// Liveness probe. /// Indicates whether the process is running. Used by orchestration systems to confirm the process is alive. /// /// /// 200 OK with JSON payload: { "status": "alive" } when the process is running. /// // GET api/health/live [HttpGet("live")] [SwaggerOperation(Summary = "Liveness probe", Description = "Returns whether the API process is alive.")] [SwaggerResponse(StatusCodes.Status200OK, "Service is alive")] [ProducesResponseType(StatusCodes.Status200OK)] public IActionResult Live() => Ok(new { status = "alive" }); /// /// Basic health check endpoint. /// Returns overall status and the current server time in UTC. /// /// /// 200 OK with JSON payload: { "status": "ok", "time": <UTC time> }. /// // GET api/health [HttpGet] [SwaggerOperation(Summary = "Health check", Description = "Returns overall health status and current UTC time.")] [SwaggerResponse(StatusCodes.Status200OK, "Health check succeeded")] [ProducesResponseType(StatusCodes.Status200OK)] public IActionResult Health() => Ok(new { status = "ok", time = DateTimeOffset.UtcNow }); /// /// Echo endpoint. /// Returns the received JSON payload unchanged. Useful for testing request/response plumbing. /// /// Arbitrary JSON from the request body. The endpoint returns the same object. /// 200 OK with the same JSON payload provided in the request body. // POST api/health/echo [HttpPost("echo")] [SwaggerOperation(Summary = "Echo payload", Description = "Returns the same JSON payload received in the request body.")] [SwaggerResponse(StatusCodes.Status200OK, "Payload echoed successfully")] [ProducesResponseType(StatusCodes.Status200OK)] public IActionResult Echo(object payload) => Ok(payload); /// /// Readiness probe. /// Indicates whether the service is ready to accept traffic. Typically checks downstream dependencies. /// /// /// 200 OK with JSON { "status": "ready" } when ready; /// 503 Service Unavailable with JSON { "status": "not_ready" } when not ready. /// // GET api/health/ready [HttpGet("ready")] [SwaggerOperation(Summary = "Readiness probe", Description = "Returns whether the service is ready to accept traffic.")] [SwaggerResponse(StatusCodes.Status200OK, "Service is ready")] [SwaggerResponse(StatusCodes.Status503ServiceUnavailable, "Service is not ready")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status503ServiceUnavailable)] public IActionResult Ready() { var ready = true; return ready ? Ok(new { status = "ready" }) : StatusCode(503, new { status = "not_ready" }); } } }