feat(http): implement main HTTP server with health endpoints #140

Merged
fuzzy merged 1 commit from feat/http-server into main 2026-08-02 21:31:13 +00:00
Owner

What

Implement the main HTTP server in internal/httpapi:

  • /healthz (#59) — liveness endpoint, returns 200 {"status":"ok"}
  • /readyz (#60) — readiness endpoint, returns 200 {"status":"ready"}; backed by an atomic readiness flag (always ready for now, ready to be driven by dependency state later)
  • NewRouter() keeps gin.Logger() + gin.Recovery() middleware

cmd/thwap-pagesd/main.go now starts the HTTP server:

  • http.Server listening on the configured listener.address
  • Graceful shutdown on SIGINT/SIGTERM with a 10s timeout
  • Logs listening address, forgejo URL, and k8s namespace at startup

Tests: httptest-based coverage for /healthz, /readyz, and 404 on unknown routes.

Why

Phase 5 task #61 — the HTTP server that the registration API (#69), webhook receiver (#75), and status API (#78) build on.

Testing

  • go build ./...
  • go vet ./...
  • go test -race ./internal/httpapi/ — 3 tests pass
  • gofmt -l ./cmd ./internal ./pkg clean
  • golangci-lint run — 0 issues
  • pre-commit hooks all pass

Breaking Changes

None.

Notes

  • The /readyz flag is currently hardcoded ready; it will be driven by service readiness in later phases.
  • Issues #59–#61 were closed via the Forgejo API as part of this task per the workflow.

Closes #59
Closes #60
Closes #61

## What Implement the main HTTP server in `internal/httpapi`: - **`/healthz` (#59)** — liveness endpoint, returns `200 {"status":"ok"}` - **`/readyz` (#60)** — readiness endpoint, returns `200 {"status":"ready"}`; backed by an atomic readiness flag (always ready for now, ready to be driven by dependency state later) - `NewRouter()` keeps `gin.Logger()` + `gin.Recovery()` middleware **`cmd/thwap-pagesd/main.go`** now starts the HTTP server: - `http.Server` listening on the configured `listener.address` - Graceful shutdown on SIGINT/SIGTERM with a 10s timeout - Logs listening address, forgejo URL, and k8s namespace at startup **Tests**: httptest-based coverage for `/healthz`, `/readyz`, and 404 on unknown routes. ## Why Phase 5 task #61 — the HTTP server that the registration API (#69), webhook receiver (#75), and status API (#78) build on. ## Testing - [x] `go build ./...` - [x] `go vet ./...` - [x] `go test -race ./internal/httpapi/` — 3 tests pass - [x] `gofmt -l ./cmd ./internal ./pkg` clean - [x] `golangci-lint run` — 0 issues - [x] pre-commit hooks all pass ## Breaking Changes None. ## Notes - The `/readyz` flag is currently hardcoded ready; it will be driven by service readiness in later phases. - Issues #59–#61 were closed via the Forgejo API as part of this task per the workflow. Closes #59 Closes #60 Closes #61
feat(http): implement main HTTP server with health endpoints
All checks were successful
Test and Release / lint (pull_request) Successful in 7m8s
Test and Release / test (pull_request) Successful in 7m13s
2dab711328
Register /healthz and /readyz endpoints on the gin router, returning
JSON status responses. /readyz uses an atomic readiness flag that is
currently always ready, ready to be driven by dependency state later.

Start the HTTP server in main with graceful shutdown on SIGINT/SIGTERM,
listening on the configured listener address.

Add httptest-based tests for the health, readiness, and 404 routes.
Mark task done in ROADMAP.md.

closes #59
closes #60
closes #61
fuzzy scheduled this pull request to auto merge when all checks succeed 2026-08-02 21:07:00 +00:00
the.auditor left a comment

Review Summary

Verified locally on the PR head (2dab711): go build, go vet, go mod verify, gofmt, golangci-lint run all clean; all 3 httpapi tests pass with -race. Also smoke-tested the binary: /healthz200 {"status":"ok"}, /readyz200 {"status":"ready"}, unknown route → 404, and SIGTERM triggers a clean graceful shutdown (log + exit 0).

The server wiring is correct — http.Server bound to the configured listener, signal.NotifyContext handling SIGINT/SIGTERM, and a 10s bounded Shutdown. The /readyz atomic flag is a sensible placeholder that's ready to be driven by dependency state later.

No blocking issues.

Non-blocking observations:

  1. The ready flag is local to NewRouter and always true with no external setter yet — fine as a placeholder, but it will need to move into a shared readiness type when services drive it (later phases).
  2. gin's Logger() middleware writes request logs to stdout while the rest of the app logs through zap — the recurring mixed-logging note; worth wiring gin into the zap logger eventually.
  3. The "listening" log fires before ListenAndServe actually binds — trivial ordering nit.

Approving.

## Review Summary Verified locally on the PR head (`2dab711`): `go build`, `go vet`, `go mod verify`, `gofmt`, `golangci-lint run` all clean; all 3 httpapi tests pass with `-race`. Also smoke-tested the binary: `/healthz` → `200 {"status":"ok"}`, `/readyz` → `200 {"status":"ready"}`, unknown route → `404`, and SIGTERM triggers a clean graceful shutdown (log + exit 0). The server wiring is correct — `http.Server` bound to the configured listener, `signal.NotifyContext` handling SIGINT/SIGTERM, and a 10s bounded `Shutdown`. The `/readyz` atomic flag is a sensible placeholder that's ready to be driven by dependency state later. **No blocking issues.** Non-blocking observations: 1. The `ready` flag is local to `NewRouter` and always true with no external setter yet — fine as a placeholder, but it will need to move into a shared readiness type when services drive it (later phases). 2. gin's `Logger()` middleware writes request logs to stdout while the rest of the app logs through zap — the recurring mixed-logging note; worth wiring gin into the zap logger eventually. 3. The "listening" log fires before `ListenAndServe` actually binds — trivial ordering nit. Approving.
fuzzy merged commit 2dab711328 into main 2026-08-02 21:31:13 +00:00
fuzzy deleted branch feat/http-server 2026-08-02 21:31:13 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
thwap/thwap-pagesd!140
No description provided.