mirror of
https://github.com/juanfont/headscale.git
synced 2026-07-08 17:10:21 +09:00
c9bbb5bdec
Reimplement the v1 API as a code-first Huma service in hscontrol/api/v1, a thin adapter over the state layer. Huma emits the OpenAPI 3.1 document (openapi/v1/headscale.yaml) from the Go operation and type definitions; cmd/gen-openapi writes it and the 3.0.3 downgrade the client is generated from. Responses reproduce the protojson wire contract (string-encoded 64-bit IDs, all fields emitted, RFC3339/null timestamps); errors map to the correct HTTP status (404/400/409, 500 for server faults) via mapError. Serve it on the chi router at /api/v1 behind the existing API-key middleware, and point /swagger at the emitted spec.
50 lines
1.6 KiB
Go
50 lines
1.6 KiB
Go
package apiv1
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"github.com/danielgtaylor/huma/v2"
|
|
"github.com/juanfont/headscale/hscontrol/db"
|
|
"github.com/juanfont/headscale/hscontrol/state"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// mapError translates a state/db-layer error into a Huma HTTP error
|
|
// (NotFound→404, invalid input→400, conflict→409, everything else→500).
|
|
// Handlers use this default mapping and may return a more specific huma.ErrorN
|
|
// directly. msg is a human context prefix, e.g. "getting node".
|
|
func mapError(msg string, err error) error {
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
switch {
|
|
case errors.Is(err, gorm.ErrRecordNotFound),
|
|
errors.Is(err, state.ErrNodeNotFound),
|
|
errors.Is(err, state.ErrNodeNotInNodeStore),
|
|
errors.Is(err, db.ErrUserNotFound),
|
|
errors.Is(err, db.ErrNodeNotFoundRegistrationCache),
|
|
errors.Is(err, state.ErrRegistrationExpired):
|
|
return huma.Error404NotFound(msg, err)
|
|
|
|
case errors.Is(err, state.ErrGivenNameInvalid),
|
|
errors.Is(err, state.ErrGivenNameTaken),
|
|
errors.Is(err, state.ErrNodeNameNotUnique),
|
|
errors.Is(err, state.ErrNodeMarkedTaggedButHasNoTags),
|
|
errors.Is(err, state.ErrNodeHasNeitherUserNorTags),
|
|
errors.Is(err, state.ErrRequestedTagsInvalidOrNotPermitted),
|
|
errors.Is(err, db.ErrUserStillHasNodes),
|
|
errors.Is(err, db.ErrCannotChangeOIDCUser),
|
|
errors.Is(err, db.ErrPreAuthKeyNotTaggedOrOwned),
|
|
errors.Is(err, db.ErrSingleUseAuthKeyHasBeenUsed):
|
|
return huma.Error400BadRequest(msg, err)
|
|
|
|
case errors.Is(err, state.ErrNodeKeyInUse),
|
|
errors.Is(err, state.ErrAmbiguousNodeOwnership):
|
|
return huma.Error409Conflict(msg, err)
|
|
|
|
default:
|
|
return huma.Error500InternalServerError(msg, err)
|
|
}
|
|
}
|