πŸ“– 4 min read (~ 900 words).

Vendor extensions

By default codescan records where each spec object came from in Go via x-go-name (and x-go-package on definitions) β€” useful for round-tripping and code generation. Options.SkipExtensions removes them for a leaner spec.

// Widget is a small model.
//
// codescan records each field's Go origin as vendor extensions unless
// SkipExtensions is set.
//
// swagger:model
type Widget struct {
	// Label is the display label.
	Label string `json:"label"`

	// Size is the widget size in pixels.
	Size int32 `json:"size"`
}

Full source: docs/examples/shaping/extensions/extensions.go

Default
{
  "description": "codescan records each field's Go origin as vendor extensions unless\nSkipExtensions is set.",
  "type": "object",
  "title": "Widget is a small model.",
  "properties": {
    "label": {
      "description": "Label is the display label.",
      "type": "string",
      "x-go-name": "Label"
    },
    "size": {
      "description": "Size is the widget size in pixels.",
      "type": "integer",
      "format": "int32",
      "x-go-name": "Size"
    }
  },
  "x-go-package": "github.com/go-openapi/codescan/docs/examples/shaping/extensions"
}

Full source: docs/examples/shaping/extensions/testdata/off.json

SkipExtensions: true
{
  "description": "codescan records each field's Go origin as vendor extensions unless\nSkipExtensions is set.",
  "type": "object",
  "title": "Widget is a small model.",
  "properties": {
    "label": {
      "description": "Label is the display label.",
      "type": "string"
    },
    "size": {
      "description": "Size is the widget size in pixels.",
      "type": "integer",
      "format": "int32"
    }
  }
}

Full source: docs/examples/shaping/extensions/testdata/on.json

codescan.Run(&codescan.Options{
    Packages:       []string{"./..."},
    ScanModels:     true,
    SkipExtensions: true,
})

SkipExtensions removes the scanner-derived x-go-* extensions. Extensions you author yourself (via the Extensions: keyword) are not affected, and neither is x-deprecated (it carries semantic intent β€” see Other type decorators).

Stamping x-go-type

x-go-name and x-go-package record where a definition came from, but not the originating type’s own name. Options.EmitXGoType adds an x-go-type extension carrying the fully-qualified Go type (<package path>.<type name>) β€” useful for round-tripping a generated spec back to its source types:

codescan.Run(&codescan.Options{
    Packages:    []string{"./..."},
    ScanModels:  true,
    EmitXGoType: true,
})
Default β€” no x-go-type
{
  "description": "codescan records each field's Go origin as vendor extensions unless\nSkipExtensions is set.",
  "type": "object",
  "title": "Widget is a small model.",
  "properties": {
    "label": {
      "description": "Label is the display label.",
      "type": "string",
      "x-go-name": "Label"
    },
    "size": {
      "description": "Size is the widget size in pixels.",
      "type": "integer",
      "format": "int32",
      "x-go-name": "Size"
    }
  },
  "x-go-package": "github.com/go-openapi/codescan/docs/examples/shaping/extensions"
}

Full source: docs/examples/shaping/extensions/testdata/off.json

EmitXGoType: true
{
  "description": "codescan records each field's Go origin as vendor extensions unless\nSkipExtensions is set.",
  "type": "object",
  "title": "Widget is a small model.",
  "properties": {
    "label": {
      "description": "Label is the display label.",
      "type": "string",
      "x-go-name": "Label"
    },
    "size": {
      "description": "Size is the widget size in pixels.",
      "type": "integer",
      "format": "int32",
      "x-go-name": "Size"
    }
  },
  "x-go-package": "github.com/go-openapi/codescan/docs/examples/shaping/extensions",
  "x-go-type": "github.com/go-openapi/codescan/docs/examples/shaping/extensions.Widget"
}

Full source: docs/examples/shaping/extensions/testdata/xgotype.json

The stamp lands on the definition, beside x-go-package. It is opt-in and default-off, so existing specs are unchanged; it is presence-guarded, so it never overwrites the deliberate x-go-type the special-type recognizers already set (error, the unmodellable generic-type fallback). Like the other x-go-* extensions it rides the SkipExtensions umbrella β€” set SkipExtensions and no x-go-type is emitted either.

Enum descriptions

A swagger:enum type backed by Go const declarations folds the constβ†’value mapping into the field’s description and duplicates it in the x-go-enum-desc extension. When the prose already says everything you want, the folded mapping is noise. Options.SkipEnumDescriptions keeps the authored prose as the description; the mapping then rides x-go-enum-desc only:

codescan.Run(&codescan.Options{
    Packages:             []string{"./..."},
    ScanModels:           true,
    SkipEnumDescriptions: true,
})

This knob is independent of SkipExtensions: set both to drop the mapping everywhere (no description folding, no x-go-enum-desc).

Authoring x-* on parameters and headers

The x-go-* extensions above are scanner-derived. To attach your own vendor extension β€” say x-example for a tool like Dredd β€” use an Extensions: block in the doc comment. It works on a model (the x-* lands on the definition), a model field, a parameter, and a response header alike. (A bare // x-example: 2 line would be read as the description; the Extensions: block is the supported form.)

// ListWidgetsParams decorates a query parameter with an author-supplied vendor
// extension through an Extensions: block β€” useful for tools (e.g. Dredd) that
// read x-example. A bare `x-example:` line would be swallowed as the
// description, so the Extensions: block is the supported form.
//
// swagger:parameters listWidgets
type ListWidgetsParams struct {
	// Page is the page number.
	//
	// in: query
	//
	// Extensions:
	//   x-example: 2
	Page int32 `json:"page"`
}

// WidgetList responds with a header that also carries a vendor extension β€”
// parameters and response headers both honour Extensions:.
//
// swagger:response widgetList
type WidgetList struct {
	// X-Rate-Limit is the per-window request budget.
	//
	// Extensions:
	//   x-units: requests-per-minute
	XRateLimit int32 `json:"X-Rate-Limit"`
}

// swagger:route GET /widgets widgets listWidgets
//
// responses:
//
//	200: widgetList

Full source: docs/examples/shaping/extensions/extensions.go

{
  "parameter": {
    "type": "integer",
    "format": "int32",
    "x-example": 2,
    "description": "Page is the page number.",
    "name": "page",
    "in": "query"
  },
  "responseHeader": {
    "type": "integer",
    "format": "int32",
    "description": "X-Rate-Limit is the per-window request budget.",
    "x-units": "requests-per-minute"
  }
}

Full source: docs/examples/shaping/extensions/testdata/paramext.json

Author-supplied extensions are not stripped by SkipExtensions β€” the fragment above is produced with SkipExtensions: true, yet x-example and x-units survive, because the flag only removes the scanner-derived x-go-* set.