docs(api/v2): keep registrar godoc attached; clarify registry concurrency + ordering

- Move each resource file's init() below its RegisterXRoutes func so the func doc
  comment stays attached (it was documenting init()).
- Note AddRouteRegistrar is init-only and not concurrency-safe.
- Reword RegisterAll: registrar order is unspecified and irrelevant.
This commit is contained in:
kolaente 2026-06-02 22:36:14 +02:00 committed by kolaente
parent 5257922f3b
commit ceb2b4f161
7 changed files with 22 additions and 15 deletions

View File

@ -31,8 +31,6 @@ type adminProjectListBody struct {
Body Paginated[*models.Project]
}
func init() { AddRouteRegistrar(RegisterAdminProjectRoutes) }
// Permissions are enforced by the gateV2AdminRoutes path middleware, not per-handler.
func RegisterAdminProjectRoutes(api huma.API) {
tags := []string{"admin"}
@ -47,6 +45,8 @@ func RegisterAdminProjectRoutes(api huma.API) {
}, adminProjectsList)
}
func init() { AddRouteRegistrar(RegisterAdminProjectRoutes) }
func adminProjectsList(ctx context.Context, in *ListParams) (*adminProjectListBody, error) {
a, err := authFromCtx(ctx)
if err != nil {

View File

@ -39,8 +39,6 @@ type avatarInput struct {
Size int64 `query:"size" default:"250" minimum:"1" doc:"Desired avatar edge length in pixels. Clamped to the server's configured maximum if larger; providers that render fixed-size images may ignore it."`
}
func init() { AddRouteRegistrar(RegisterAvatarRoutes) }
// RegisterAvatarRoutes wires the avatar binary endpoint onto the Huma API.
func RegisterAvatarRoutes(api huma.API) {
Register(api, huma.Operation{
@ -68,6 +66,8 @@ func RegisterAvatarRoutes(api huma.API) {
}, avatarGet)
}
func init() { AddRouteRegistrar(RegisterAvatarRoutes) }
func avatarGet(ctx context.Context, in *avatarInput) (*avatarResponse, error) {
// Authenticated but no per-user check — any authenticated caller may view any
// avatar (matching v1); authFromCtx just surfaces a clean 401 if auth is missing.

View File

@ -41,8 +41,6 @@ type avatarUploadBody struct {
Body *models.Message
}
func init() { AddRouteRegistrar(RegisterAvatarUploadRoutes) }
func RegisterAvatarUploadRoutes(api huma.API) {
tags := []string{"user"}
@ -60,6 +58,8 @@ func RegisterAvatarUploadRoutes(api huma.API) {
}, avatarUpload)
}
func init() { AddRouteRegistrar(RegisterAvatarUploadRoutes) }
func avatarUpload(ctx context.Context, in *avatarUploadInput) (*avatarUploadBody, error) {
a, err := authFromCtx(ctx)
if err != nil {

View File

@ -35,8 +35,6 @@ type labelListBody struct {
Body Paginated[*models.LabelWithTaskID]
}
func init() { AddRouteRegistrar(RegisterLabelRoutes) }
// RegisterLabelRoutes wires Label CRUD onto the Huma API.
func RegisterLabelRoutes(api huma.API) {
tags := []string{"labels"}
@ -87,6 +85,8 @@ func RegisterLabelRoutes(api huma.API) {
}, labelsDelete)
}
func init() { AddRouteRegistrar(RegisterLabelRoutes) }
func labelsList(ctx context.Context, in *ListParams) (*labelListBody, error) {
a, err := authFromCtx(ctx)
if err != nil {

View File

@ -34,8 +34,6 @@ type projectViewListBody struct {
Body Paginated[*models.ProjectView]
}
func init() { AddRouteRegistrar(RegisterProjectViewRoutes) }
// RegisterProjectViewRoutes wires the nested ProjectView CRUD onto the Huma API.
// Every operation binds two path params: {project} → ProjectID and {view} → ID.
// This is the reference shape every nested sub-resource copies.
@ -88,6 +86,8 @@ func RegisterProjectViewRoutes(api huma.API) {
}, projectViewsDelete)
}
func init() { AddRouteRegistrar(RegisterProjectViewRoutes) }
func projectViewsList(ctx context.Context, in *struct {
ProjectID int64 `path:"project"`
ListParams

View File

@ -23,14 +23,20 @@ var routeRegistrars []func(huma.API)
// AddRouteRegistrar records a resource's route-registration function. Each
// resource file calls this from an init() so new resources never touch the
// central wiring.
//
// It mutates the package-level routeRegistrars slice without synchronization, so
// it is NOT safe for concurrent use. Call it only during package initialization
// (from an init() func), never at runtime.
func AddRouteRegistrar(f func(huma.API)) {
routeRegistrars = append(routeRegistrars, f)
}
// RegisterAll runs every registrar collected via AddRouteRegistrar, then
// enables AutoPatch. Registrars run in init() order (filename order across the
// package); the order they register routes in is irrelevant. AutoPatch runs
// last so it can synthesise PATCH counterparts for all GET + PUT pairs.
// enables AutoPatch. The order in which registrars run is unspecified (Go does
// not guarantee a stable init order across files) and does not matter: each
// resource registers a distinct set of routes. AutoPatch runs last — inside
// RegisterAll, after every registrar — so it can synthesise PATCH counterparts
// for all GET + PUT pairs.
func RegisterAll(api huma.API) {
for _, r := range routeRegistrars {
r(api)

View File

@ -27,8 +27,7 @@ import (
)
// RegisterTaskDuplicateRoutes wires the task-duplicate action onto the Huma API.
func init() { AddRouteRegistrar(RegisterTaskDuplicateRoutes) }
//
// TaskDuplicate is a CRUDable Create, so the handler reuses handler.DoCreate
// (its CanCreate enforces read-source + write-project); the only custom part is
// taking TaskID from the path rather than a request body.
@ -45,6 +44,8 @@ func RegisterTaskDuplicateRoutes(api huma.API) {
}, tasksDuplicate)
}
func init() { AddRouteRegistrar(RegisterTaskDuplicateRoutes) }
func tasksDuplicate(ctx context.Context, in *struct {
TaskID int64 `path:"projecttask" doc:"The numeric id of the task to duplicate."`
}) (*singleBody[models.TaskDuplicate], error) {