Overriding titles & descriptions
A Go doc comment is written for Go readers. The same prose is not always what
you want in the published API — a comment may explain internal usage, reference
Go types, or simply read awkwardly to an API consumer. swagger:title and
swagger:description let the spec text diverge from the godoc: the
annotation replaces the prose-derived value, leaving the Go comment free to say
whatever Go developers need.
This is the explicit counterpart to
Single-line comments,
which controls how a plain comment is implicitly routed to title vs
description. Each pane below pairs the annotated Go (left) with the exact
fragment the scanner emits (right), from the test-covered
docs/examples/shaping/overrides
package.
Overriding a model and its fields
swagger:title <text> sets the title; swagger:description <text> sets the
description. Both sit in the comment block beside swagger:model (on a type)
or beside a field’s other keywords. The model’s Go-facing godoc here is replaced
wholesale by the two overrides:
// Widget is the Go-facing widget doc, written for Go readers.
//
// It explains internal Go usage that should not leak into the API spec.
//
// swagger:model
// swagger:title A Public Widget
// swagger:description A widget exposed via the public API.
type Widget struct {
// ID explains the Go field for Go readers.
//
// swagger:description The unique widget identifier.
ID string `json:"id"`
// Label is the Go-facing field doc. Fields carry no title by default;
// the override is the only way a property gets one.
//
// swagger:title Display Label
// swagger:description Human-readable label shown to API consumers.
Label string `json:"label"`
// Plain keeps its godoc description because it carries no override.
Plain string `json:"plain"`
// Capacity combines a description override with an inline validation
// keyword on the same field: the override applies AND maximum is kept,
// because the override annotations dispatch through the schema family.
//
// swagger:description The maximum capacity, in liters.
// maximum: 1000
Capacity int64 `json:"capacity"`
// Suppressed has a godoc that a bare swagger:description suppresses: the
// empty value is applied (description omitted) and scan.empty-override is
// raised, in case the bare marker was left behind by mistake.
//
// swagger:description
Suppressed string `json:"suppressed"`
// Notes carries a multi-line description override: the lines following the
// annotation fold into the description until the blank line, joined with
// newlines.
//
// swagger:description Free-form notes about the widget.
// They may span several lines, all folded into one description.
//
// The blank line above terminates the override body; this paragraph is
// ordinary godoc and is discarded (the override won).
Notes string `json:"notes"`
// Gadget is a $ref field carrying title + description overrides. They are
// symmetric $ref siblings: kept under EmitRefSiblings, dropped to a bare
// $ref under the default flags — the same rule a prose description follows.
//
// swagger:title Gadget Ref
// swagger:description The attached gadget, described for API consumers.
Gadget Gadget `json:"gadget"`
}
// Gadget is a plain referenced model.
//
// swagger:model
type Gadget struct {
Serial string `json:"serial"`
}Full source: docs/examples/shaping/overrides/overrides.go
{
"description": "A widget exposed via the public API.",
"type": "object",
"title": "A Public Widget",
"properties": {
"capacity": {
"description": "The maximum capacity, in liters.",
"type": "integer",
"format": "int64",
"maximum": 1000,
"x-go-name": "Capacity"
},
"gadget": {
"$ref": "#/definitions/Gadget"
},
"id": {
"description": "The unique widget identifier.",
"type": "string",
"x-go-name": "ID"
},
"label": {
"description": "Human-readable label shown to API consumers.",
"type": "string",
"title": "Display Label",
"x-go-name": "Label"
},
"notes": {
"description": "Free-form notes about the widget.\nThey may span several lines, all folded into one description.",
"type": "string",
"x-go-name": "Notes"
},
"plain": {
"description": "Plain keeps its godoc description because it carries no override.",
"type": "string",
"x-go-name": "Plain"
},
"suppressed": {
"type": "string",
"x-go-name": "Suppressed"
}
},
"x-go-package": "github.com/go-openapi/codescan/docs/examples/shaping/overrides"
}
Full source: docs/examples/shaping/overrides/testdata/widget.json
A few things to read out of that pane:
titleon a property comes only from an override. A field’s godoc becomes itsdescription; codescan never derives a propertytitlefrom prose, soswagger:title(as onlabel) is the only way to set one.plainkeeps its godoc — no override means no change. Overrides are strictly opt-in; un-annotated declarations behave exactly as before.
Multi-line descriptions
swagger:description may span several lines. The lines immediately following
the annotation fold into one description (joined with newlines) and the body
terminates at the first blank line, keyword, annotation, or end of comment.
The notes field above shows this: its two prose lines fold together, and the
ordinary godoc paragraph after the blank line is discarded.
To carry a body past a blank line — a markdown table, a multi-paragraph
description — end the annotation line with a | literal block marker; see
Markdown descriptions.
Keeping a co-located validation keyword
Because the override annotations dispatch through the schema family, a
validation keyword on the same field still applies — they co-exist rather
than one shadowing the other. The capacity field carries both
swagger:description and maximum: 1000, and the output keeps both.
Suppressing a godoc comment
A bare swagger:description (no text, empty body) applies the empty value
— a deliberate way to drop a godoc comment from the spec without deleting it
from the source. Because a stray bare marker could also be an accident,
codescan raises a scan.empty-override warning through OnDiagnostic. The
suppressed field above emits no description at all.
Overrides beside a $ref
title and description are symmetric $ref siblings: on a field whose Go
type is a referenced model, they follow the same preservation rule a prose
description does. Under the default flags they drop to a bare $ref; with
EmitRefSiblings
they ride alongside the $ref as direct siblings.
{
"$ref": "#/definitions/Gadget"
}
Full source: docs/examples/shaping/overrides/testdata/gadget_bare.json
{
"description": "The attached gadget, described for API consumers.",
"title": "Gadget Ref",
"$ref": "#/definitions/Gadget"
}
Full source: docs/examples/shaping/overrides/testdata/gadget_siblings.json
Responses and headers
swagger:description also overrides the description of a swagger:response and
of its response headers. OpenAPI 2.0 Response and Header objects have no
title field, so a swagger:title on a response or header is rejected with a
parse.context-invalid diagnostic — the description override still applies.
// ErrorResponse is the Go-facing response doc, written for Go readers — it
// should not leak into the API spec.
//
// swagger:response errorResponse
// swagger:description The error payload returned to API consumers.
// swagger:title Ignored — responses have no title
type ErrorResponse struct {
// XErrorCode is the Go-facing header doc.
//
// swagger:description The machine-readable error code.
XErrorCode string `json:"X-Error-Code"`
// ErrorBody carries the structured error.
//
// in: body
Body ErrorBody `json:"body"`
}
// ErrorBody is the error payload returned in the response body.
//
// swagger:model
type ErrorBody struct {
Message string `json:"message"`
}Full source: docs/examples/shaping/overrides/overrides.go
{
"description": "The error payload returned to API consumers.",
"schema": {
"$ref": "#/definitions/ErrorBody"
},
"headers": {
"X-Error-Code": {
"type": "string",
"description": "The machine-readable error code."
}
}
}
Full source: docs/examples/shaping/overrides/testdata/errorresponse.json
Info
Precedence. An override always wins over the godoc-derived value. Absent →
the godoc is used unchanged. Empty (bare marker) → the empty value is applied
and scan.empty-override is raised. swagger:title is schema-only; on a
response/header it is dropped with parse.context-invalid.
What’s next
- Single-line comments
— the implicit
titlevsdescriptionrouting this overrides. - Descriptions beside a
$ref— theEmitRefSiblingsrule that title/description ride.