📖 6 min read (~ 1300 words).

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:

  • title on a property comes only from an override. A field’s godoc becomes its description; codescan never derives a property title from prose, so swagger:title (as on label) is the only way to set one.
  • plain keeps 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.

Default — dropped to a bare $ref
{
  "$ref": "#/definitions/Gadget"
}

Full source: docs/examples/shaping/overrides/testdata/gadget_bare.json

EmitRefSiblings — kept as siblings
{
  "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