Skip to content

Commit 1716a84

Browse files
committed
feat(api): add support for HEAD requests to /healthz endpoint
- Refactored `/healthz` handler to support `HEAD` requests alongside `GET`. - Updated tests to include validation for `HEAD` requests with expected status and empty body. Closes: router-for-me#2929
1 parent e6866ff commit 1716a84

2 files changed

Lines changed: 39 additions & 17 deletions

File tree

internal/api/server.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,9 +319,16 @@ func NewServer(cfg *config.Config, authManager *auth.Manager, accessManager *sdk
319319
// setupRoutes configures the API routes for the server.
320320
// It defines the endpoints and associates them with their respective handlers.
321321
func (s *Server) setupRoutes() {
322-
s.engine.GET("/healthz", func(c *gin.Context) {
322+
healthzHandler := func(c *gin.Context) {
323+
if c.Request.Method == http.MethodHead {
324+
c.Status(http.StatusOK)
325+
return
326+
}
327+
323328
c.JSON(http.StatusOK, gin.H{"status": "ok"})
324-
})
329+
}
330+
s.engine.GET("/healthz", healthzHandler)
331+
s.engine.HEAD("/healthz", healthzHandler)
325332

326333
s.engine.GET("/management.html", s.serveManagementControlPanel)
327334
openaiHandlers := openai.NewOpenAIAPIHandler(s.handlers)

internal/api/server_test.go

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,23 +50,38 @@ func newTestServer(t *testing.T) *Server {
5050
func TestHealthz(t *testing.T) {
5151
server := newTestServer(t)
5252

53-
req := httptest.NewRequest(http.MethodGet, "/healthz", nil)
54-
rr := httptest.NewRecorder()
55-
server.engine.ServeHTTP(rr, req)
53+
t.Run("GET", func(t *testing.T) {
54+
req := httptest.NewRequest(http.MethodGet, "/healthz", nil)
55+
rr := httptest.NewRecorder()
56+
server.engine.ServeHTTP(rr, req)
5657

57-
if rr.Code != http.StatusOK {
58-
t.Fatalf("unexpected status code: got %d want %d; body=%s", rr.Code, http.StatusOK, rr.Body.String())
59-
}
58+
if rr.Code != http.StatusOK {
59+
t.Fatalf("unexpected status code: got %d want %d; body=%s", rr.Code, http.StatusOK, rr.Body.String())
60+
}
6061

61-
var resp struct {
62-
Status string `json:"status"`
63-
}
64-
if err := json.Unmarshal(rr.Body.Bytes(), &resp); err != nil {
65-
t.Fatalf("failed to parse response JSON: %v; body=%s", err, rr.Body.String())
66-
}
67-
if resp.Status != "ok" {
68-
t.Fatalf("unexpected response status: got %q want %q", resp.Status, "ok")
69-
}
62+
var resp struct {
63+
Status string `json:"status"`
64+
}
65+
if err := json.Unmarshal(rr.Body.Bytes(), &resp); err != nil {
66+
t.Fatalf("failed to parse response JSON: %v; body=%s", err, rr.Body.String())
67+
}
68+
if resp.Status != "ok" {
69+
t.Fatalf("unexpected response status: got %q want %q", resp.Status, "ok")
70+
}
71+
})
72+
73+
t.Run("HEAD", func(t *testing.T) {
74+
req := httptest.NewRequest(http.MethodHead, "/healthz", nil)
75+
rr := httptest.NewRecorder()
76+
server.engine.ServeHTTP(rr, req)
77+
78+
if rr.Code != http.StatusOK {
79+
t.Fatalf("unexpected status code: got %d want %d; body=%s", rr.Code, http.StatusOK, rr.Body.String())
80+
}
81+
if rr.Body.Len() != 0 {
82+
t.Fatalf("expected empty body for HEAD request, got %q", rr.Body.String())
83+
}
84+
})
7085
}
7186

7287
func TestAmpProviderModelRoutes(t *testing.T) {

0 commit comments

Comments
 (0)