From 2602f723c3436e9216c18d1626d578621b78755c Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 31 May 2026 11:11:29 +0200 Subject: [PATCH] docs(api/v2): add field and operation descriptions for labels v2's OpenAPI spec is generated from struct tags and Operation fields at runtime; unlike swaggo (v1) it can't read Go doc comments, so v2 shipped without the field/operation descriptions v1 has. Add doc: tags to the Label model (kept in sync with the existing comments swaggo reads for v1) and Summary/Description to each label operation. Makes labels a complete reference for the pattern. --- pkg/models/label.go | 14 +++++++------- pkg/routes/api/v2/huma.go | 14 ++++++++++++++ pkg/routes/api/v2/labels.go | 10 ++++++++++ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/pkg/models/label.go b/pkg/models/label.go index 3df013f73..3725811bb 100644 --- a/pkg/models/label.go +++ b/pkg/models/label.go @@ -29,22 +29,22 @@ import ( // Label represents a label type Label struct { // The unique, numeric id of this label. - ID int64 `xorm:"bigint autoincr not null unique pk" json:"id" param:"label"` + ID int64 `xorm:"bigint autoincr not null unique pk" json:"id" param:"label" doc:"The unique, numeric id of this label."` // The title of the label. You'll see this one on tasks associated with it. - Title string `xorm:"varchar(250) not null" json:"title" valid:"runelength(1|250)" minLength:"1" maxLength:"250"` + Title string `xorm:"varchar(250) not null" json:"title" valid:"runelength(1|250)" minLength:"1" maxLength:"250" doc:"The title of the label. You'll see this one on tasks associated with it."` // The label description. - Description string `xorm:"longtext null" json:"description"` + Description string `xorm:"longtext null" json:"description" doc:"The label description."` // The color this label has in hex format. - HexColor string `xorm:"varchar(6) null" json:"hex_color" valid:"runelength(0|7)" maxLength:"7"` + HexColor string `xorm:"varchar(6) null" json:"hex_color" valid:"runelength(0|7)" maxLength:"7" doc:"The color this label has in hex format."` CreatedByID int64 `xorm:"bigint not null" json:"-"` // The user who created this label - CreatedBy *user.User `xorm:"-" json:"created_by"` + CreatedBy *user.User `xorm:"-" json:"created_by" doc:"The user who created this label."` // A timestamp when this label was created. You cannot change this value. - Created time.Time `xorm:"created not null" json:"created"` + Created time.Time `xorm:"created not null" json:"created" doc:"A timestamp when this label was created. You cannot change this value."` // A timestamp when this label was last updated. You cannot change this value. - Updated time.Time `xorm:"updated not null" json:"updated"` + Updated time.Time `xorm:"updated not null" json:"updated" doc:"A timestamp when this label was last updated. You cannot change this value."` web.CRUDable `xorm:"-" json:"-"` web.Permissions `xorm:"-" json:"-"` diff --git a/pkg/routes/api/v2/huma.go b/pkg/routes/api/v2/huma.go index 720a5929d..ce8614a03 100644 --- a/pkg/routes/api/v2/huma.go +++ b/pkg/routes/api/v2/huma.go @@ -102,4 +102,18 @@ func Register[I, O any](api huma.API, op huma.Operation, handler func(context.Co // registered GET + PUT. Must be called AFTER all Register* calls. func EnableAutoPatch(api huma.API) { autopatch.AutoPatch(api) + + // AutoPatch names each synthesised PATCH after the GET operation + // ("Patch labels-read"), which reads poorly in the docs nav. Rewrite + // the summary from the sibling PUT so it reads like "Update a label + // (partial)". Only touch summaries AutoPatch generated (the "Patch " + // prefix) so a hand-registered PATCH is left alone. + for _, item := range api.OpenAPI().Paths { + if item == nil || item.Patch == nil || item.Put == nil { + continue + } + if item.Put.Summary != "" && strings.HasPrefix(item.Patch.Summary, "Patch ") { + item.Patch.Summary = item.Put.Summary + " (partial)" + } + } } diff --git a/pkg/routes/api/v2/labels.go b/pkg/routes/api/v2/labels.go index 9dc77e076..541ab1bb2 100644 --- a/pkg/routes/api/v2/labels.go +++ b/pkg/routes/api/v2/labels.go @@ -41,6 +41,8 @@ func RegisterLabelRoutes(api huma.API) { Register(api, huma.Operation{ OperationID: "labels-list", + Summary: "List labels", + Description: "Returns the labels visible to the authenticated user — their own plus any used on tasks they can access. Not a global list.", Method: http.MethodGet, Path: "/labels", Tags: tags, @@ -48,6 +50,8 @@ func RegisterLabelRoutes(api huma.API) { Register(api, huma.Operation{ OperationID: "labels-read", + Summary: "Get a label", + Description: "Returns a single label. Sends an ETag; pass it as If-None-Match on a later read to get a 304 Not Modified.", Method: http.MethodGet, Path: "/labels/{id}", Tags: tags, @@ -55,6 +59,8 @@ func RegisterLabelRoutes(api huma.API) { Register(api, huma.Operation{ OperationID: "labels-create", + Summary: "Create a label", + Description: "Creates a label; the authenticated user becomes its owner.", Method: http.MethodPost, Path: "/labels", Tags: tags, @@ -62,6 +68,8 @@ func RegisterLabelRoutes(api huma.API) { Register(api, huma.Operation{ OperationID: "labels-update", + Summary: "Update a label", + Description: "Replaces all of a label's fields — only the owner may update it. Use PATCH for a partial update.", Method: http.MethodPut, Path: "/labels/{id}", Tags: tags, @@ -69,6 +77,8 @@ func RegisterLabelRoutes(api huma.API) { Register(api, huma.Operation{ OperationID: "labels-delete", + Summary: "Delete a label", + Description: "Deletes a label. Only the owner may delete it.", Method: http.MethodDelete, Path: "/labels/{id}", Tags: tags,