📖 4 min read (~ 800 words).

Other type decorators

Beyond validations, a couple of keyword decorators annotate a property’s or operation’s role. The panes below pair the annotated Go with the fragment the scanner emits, from the test-covered docs/examples/concepts/decorators package.

For the value shapes and legal contexts of each, see the Keyword reference.

readOnly

read only: true on a model field marks the property readOnly — the server sets it, clients must not.

Annotated Go
// Token is issued by the server.
//
// swagger:model
type Token struct {
	// ID is assigned by the server and cannot be set by clients.
	//
	// read only: true
	ID string `json:"id"`

	// Value is the token value.
	Value string `json:"value"`
}

Full source: docs/examples/concepts/decorators/decorators.go

{
  "type": "object",
  "title": "Token is issued by the server.",
  "properties": {
    "id": {
      "description": "ID is assigned by the server and cannot be set by clients.",
      "type": "string",
      "x-go-name": "ID",
      "readOnly": true
    },
    "value": {
      "description": "Value is the token value.",
      "type": "string",
      "x-go-name": "Value"
    }
  },
  "x-go-package": "github.com/go-openapi/codescan/docs/examples/concepts/decorators"
}

Full source: docs/examples/concepts/decorators/testdata/readonly.json

This is the idiomatic way to model server-set fields (an id, a createdAt) that appear in responses but should not be supplied on create — one model, marked readOnly, rather than separate request/response structs. (codescan does not hide fields per operation; if you truly need different shapes, declare distinct request and response models.)

deprecated

deprecated: true in a swagger:route / swagger:operation body marks the operation deprecated.

Annotated Go
// swagger:route GET /legacy/ping legacy ping
//
// Ping is the legacy health check.
//
// deprecated: true
//
// responses:
//
//	200: pingResponse


// Gadget is a deprecated model. OpenAPI 2.0 has no native `deprecated` on a
// schema, so codescan emits `x-deprecated: true` — here triggered by the
// godoc-style "Deprecated:" paragraph, which is recognised on its own without a
// separate annotation. (The explicit `deprecated: true` annotation, shown on the
// operation above, has the same effect on a model or field.)
//
// Deprecated: superseded by the v2 widget API.
//
// swagger:model
type Gadget struct {
	// SerialNo is the legacy identifier.
	//
	// Deprecated: use the v2 identifier instead.
	SerialNo string `json:"serialNo"`

	// Name is the current display name.
	Name string `json:"name"`
}

Full source: docs/examples/concepts/decorators/decorators.go

paths[/legacy/ping]
{
  "get": {
    "tags": [
      "legacy"
    ],
    "summary": "Ping is the legacy health check.",
    "operationId": "ping",
    "deprecated": true,
    "responses": {
      "200": {
        "$ref": "#/responses/pingResponse"
      }
    }
  }
}

Full source: docs/examples/concepts/decorators/testdata/deprecated.json

Info

On an operation, deprecated: true sets the native OpenAPI 2.0 deprecated field. OpenAPI 2.0 has no native deprecated on the Schema object, so on a model or model field codescan emits the x-deprecated: true vendor extension instead.

A godoc-style Deprecated: paragraph (the pkgsite convention) is an exact synonym for deprecated: true, recognised in any context. On a Go doc comment it is the natural form — a bare // deprecated: true line there reads as a malformed deprecation notice to Go linters, whereas the capitalised Deprecated: paragraph is idiomatic. Use deprecated: true in the indented route / operation bodies, and the Deprecated: paragraph on model and field doc comments; either yields the same result. x-deprecated carries semantic intent rather than reflection metadata, so it is emitted even when SkipExtensions is set.

A godoc Deprecated: paragraph marks a model and its fields — codescan emits x-deprecated: true on each (the explicit deprecated: true annotation has the same effect):

Annotated Go
// Gadget is a deprecated model. OpenAPI 2.0 has no native `deprecated` on a
// schema, so codescan emits `x-deprecated: true` — here triggered by the
// godoc-style "Deprecated:" paragraph, which is recognised on its own without a
// separate annotation. (The explicit `deprecated: true` annotation, shown on the
// operation above, has the same effect on a model or field.)
//
// Deprecated: superseded by the v2 widget API.
//
// swagger:model
type Gadget struct {
	// SerialNo is the legacy identifier.
	//
	// Deprecated: use the v2 identifier instead.
	SerialNo string `json:"serialNo"`

	// Name is the current display name.
	Name string `json:"name"`
}

Full source: docs/examples/concepts/decorators/decorators.go

#/definitions/Gadget
{
  "description": "Deprecated: superseded by the v2 widget API.",
  "type": "object",
  "title": "Gadget is a deprecated model. OpenAPI 2.0 has no native `deprecated` on a\nschema, so codescan emits `x-deprecated: true` — here triggered by the\ngodoc-style \"Deprecated:\" paragraph, which is recognised on its own without a\nseparate annotation. (The explicit `deprecated: true` annotation, shown on the\noperation above, has the same effect on a model or field.)",
  "properties": {
    "name": {
      "description": "Name is the current display name.",
      "type": "string",
      "x-go-name": "Name"
    },
    "serialNo": {
      "description": "SerialNo is the legacy identifier.\n\nDeprecated: use the v2 identifier instead.",
      "type": "string",
      "x-deprecated": true,
      "x-go-name": "SerialNo"
    }
  },
  "x-deprecated": true,
  "x-go-package": "github.com/go-openapi/codescan/docs/examples/concepts/decorators"
}

Full source: docs/examples/concepts/decorators/testdata/deprecated_model.json

What’s next