Descriptions beside a $ref
When a struct field’s Go type resolves to a named model, the field becomes a
$ref. Strict JSON Schema draft 4 (the dialect OpenAPI 2.0 is built on) says a
$ref replaces its siblings — so a description, a validation, or an x-*
extension written on that field cannot simply sit next to the $ref.
codescan’s default is to preserve those decorations by wrapping the reference in
an allOf compound, which is the draft-4-correct shape. Three options tune
this behaviour. The decorations split into two classes:
- description & extensions — siblings-eligible: modern tooling (OpenAPI
3.1 / JSON Schema 2020-12, most Swagger-UI renderers) reads them directly
beside a
$ref. - validations &
externalDocs— compound-only: they have no valid bare-$refform, so they can only ride anallOfcompound.
// Address is a referenced model.
//
// swagger:model
type Address struct {
// Street is the street line.
Street string `json:"street"`
}
// Person references Address through a field decorated with a description and a
// vendor extension — both can, in principle, sit beside the $ref. How they are
// rendered depends on the options.
//
// swagger:model
type Person struct {
// Home is where the person lives.
//
// extensions:
// x-ui-order: 3
Home Address `json:"home"`
}Full source: docs/examples/shaping/refsiblings/refsiblings.go
The default — an allOf wrapper
With no options set, the field’s description and extension are preserved by
wrapping the $ref as the single member of an allOf; the decorations ride the
outer schema:
{
"description": "Home is where the person lives.",
"allOf": [
{
"$ref": "#/definitions/Address"
}
],
"x-go-name": "Home",
"x-ui-order": 3
}
Full source: docs/examples/shaping/refsiblings/testdata/default.json
This is the always-correct shape and needs no configuration — see also
Decorating a $ref in the
Model definitions tutorial.
Emit siblings directly — EmitRefSiblings
Set Options.EmitRefSiblings to render the description and extensions as
direct siblings of the $ref, with no allOf wrapper — the leaner shape
modern tools expect:
{
"description": "Home is where the person lives.",
"allOf": [
{
"$ref": "#/definitions/Address"
}
],
"x-go-name": "Home",
"x-ui-order": 3
}
Full source: docs/examples/shaping/refsiblings/testdata/default.json
{
"description": "Home is where the person lives.",
"x-ui-order": 3,
"$ref": "#/definitions/Address"
}
Full source: docs/examples/shaping/refsiblings/testdata/siblings.json
Info
EmitRefSiblings only changes the cases where nothing else forces a compound.
When the field also carries a validation or externalDocs (which cannot
live beside a bare $ref), the allOf wrapper is still emitted and the
description / extensions ride its outer schema.
Drop the compound entirely — SkipAllOfCompounding
Some downstream consumers — notably go-swagger’s code generator — expect a field
that points at a model to be a bare $ref and do not handle the
allOf-compounded shape. Set Options.SkipAllOfCompounding to never emit an
allOf compound:
No compound is produced, so validations and externalDocs are dropped, and the
description and extension go with them — leaving a bare $ref:
{
"$ref": "#/definitions/Address"
}
Full source: docs/examples/shaping/refsiblings/testdata/skip.json
Every dropped decoration is reported through Options.OnDiagnostic (code
validate.dropped-ref-sibling), so the loss is never silent. Combine it with
EmitRefSiblings to keep the description and extensions as siblings while still
dropping the compound-only validations:
Note
required: is never affected by any of these options. It is a property of the
parent object (it lands in the parent’s required list), not a sibling of the
$ref, so it is always preserved.
DescWithRef (deprecated)
Options.DescWithRef predates EmitRefSiblings and covers only the narrow
description-only case: a $ref’d field whose sole decoration is a
description. By default that description is dropped; DescWithRef preserves it
by wrapping the $ref in a single-arm allOf.
{
"description": "Person references Address through a field whose only decoration is a\ndescription.",
"type": "object",
"properties": {
"home": {
"$ref": "#/definitions/Address"
}
},
"x-go-package": "github.com/go-openapi/codescan/docs/examples/shaping/descref"
}
Full source: docs/examples/shaping/descref/testdata/off.json
{
"description": "Person references Address through a field whose only decoration is a\ndescription.",
"type": "object",
"properties": {
"home": {
"description": "Home is where the person lives.",
"allOf": [
{
"$ref": "#/definitions/Address"
}
],
"x-go-name": "Home"
}
},
"x-go-package": "github.com/go-openapi/codescan/docs/examples/shaping/descref"
}
Full source: docs/examples/shaping/descref/testdata/on.json
Warning
DescWithRef is deprecated — prefer EmitRefSiblings, which preserves both
descriptions and extensions (as direct siblings). DescWithRef keeps its
original behaviour for compatibility and is a no-op when EmitRefSiblings is
set.