Files
headscale/hscontrol/api/v1/server.go
T
Kristoffer Dalby 562fcc1401 hscontrol: serve v1 API via ogen, replace grpc-gateway facade
Mount the ogen-generated server at /api/v1 with bearer-auth and RFC 7807
errors backed by the state layer; gRPC servers stay for the CLI. Add a
servertest API client harness and Health parity tests.
2026-06-19 05:57:03 +00:00

54 lines
1.8 KiB
Go

// Package apiv1 implements the Headscale v1 HTTP API: thin handlers that
// adapt the ogen-generated server interface ([oas.Handler]) onto the shared
// state layer ([state.State]). Business logic lives in the state layer; these
// handlers only translate between HTTP request/response types and state calls.
//
// The package deliberately does not import the parent hscontrol package: it
// depends only on state, types, and the generated API package, so that
// hscontrol can mount it without an import cycle.
package apiv1
import (
"net/http"
oas "github.com/juanfont/headscale/gen/api/v1"
"github.com/juanfont/headscale/hscontrol/state"
"github.com/juanfont/headscale/hscontrol/types"
"github.com/juanfont/headscale/hscontrol/types/change"
)
// Server implements the generated [oas.Handler] and [oas.SecurityHandler].
//
// Operations that have not been migrated from the gRPC stack yet are inherited
// from [oas.UnimplementedHandler] and return 501; each resource group replaces
// its stubs as it is converted.
type Server struct {
oas.UnimplementedHandler
state *state.State
cfg *types.Config
change changeFunc
}
// changeFunc distributes state changes to connected nodes. In production this
// is [github.com/juanfont/headscale/hscontrol.Headscale.Change]; tests may pass
// a no-op or a recorder.
type changeFunc func(...change.Change)
// NewHandler builds the v1 API as an [http.Handler] ready to mount at
// /api/v1. changeFn distributes [change.Change]s produced by mutating
// operations; it must not be nil (pass a no-op if changes are irrelevant).
func NewHandler(
st *state.State,
cfg *types.Config,
changeFn func(...change.Change),
) (http.Handler, error) {
s := &Server{
state: st,
cfg: cfg,
change: changeFn,
}
return oas.NewServer(s, s, oas.WithErrorHandler(errorHandler))
}