1use axum::{
2 http::StatusCode,
3 response::{IntoResponse, Response},
4 Json,
5};
6use serde::Serialize;
7
8#[derive(Debug, Clone, Serialize)]
25#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
26pub struct HealthResponse {
27 #[cfg_attr(feature = "openapi", schema(value_type = String, example = "ok"))]
28 pub status: &'static str,
29 #[serde(skip)]
30 status_code: StatusCode,
31}
32
33impl HealthResponse {
34 pub const fn ok() -> Self {
36 Self {
37 status: "ok",
38 status_code: StatusCode::OK,
39 }
40 }
41
42 pub const fn degraded() -> Self {
47 Self {
48 status: "degraded",
49 status_code: StatusCode::OK,
50 }
51 }
52
53 pub const fn unhealthy() -> Self {
58 Self {
59 status: "unhealthy",
60 status_code: StatusCode::SERVICE_UNAVAILABLE,
61 }
62 }
63}
64
65impl IntoResponse for HealthResponse {
66 fn into_response(self) -> Response {
67 (self.status_code, Json(self)).into_response()
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn ok_has_correct_status() {
77 let r = HealthResponse::ok();
78 assert_eq!(r.status, "ok");
79 assert_eq!(r.status_code, StatusCode::OK);
80 }
81
82 #[test]
83 fn degraded_has_correct_status() {
84 let r = HealthResponse::degraded();
85 assert_eq!(r.status, "degraded");
86 assert_eq!(r.status_code, StatusCode::OK);
87 }
88
89 #[test]
90 fn unhealthy_has_correct_status() {
91 let r = HealthResponse::unhealthy();
92 assert_eq!(r.status, "unhealthy");
93 assert_eq!(r.status_code, StatusCode::SERVICE_UNAVAILABLE);
94 }
95
96 #[test]
97 fn serializes_status_field_only() {
98 let r = HealthResponse::ok();
99 let v = serde_json::to_value(&r).unwrap();
100 assert_eq!(v["status"], "ok");
101 assert!(v.get("status_code").is_none());
102 }
103}