Model definitions
A definitions entry is the most common thing you ask codescan to produce. This
page walks the annotations that create and shape one, from the plain
swagger:model struct to the per-type overrides. Each pane pairs the annotated
Go (left) with the exact fragment the scanner emits (right) — both come from the
test-covered docs/examples/concepts/models
package.
For the exhaustive rule on any annotation below, follow its link to the Maintainers reference.
swagger:model
swagger:model publishes a Go struct as a definition. Field doc comments become
property descriptions; json tags drive the property names; the Go type drives
the JSON-Schema type / format. Well-known standard-library types resolve
automatically — a time.Time field, for instance, is published as
{type: string, format: date-time}.
// Pet is a single pet in the store.
//
// swagger:model
type Pet struct {
// ID is the unique identifier.
ID int64 `json:"id"`
// Name is the pet's display name.
Name string `json:"name"`
// Tags categorise the pet.
Tags []string `json:"tags,omitempty"`
}Full source: docs/examples/concepts/models/models.go
{
"type": "object",
"title": "Pet is a single pet in the store.",
"properties": {
"id": {
"description": "ID is the unique identifier.",
"type": "integer",
"format": "int64",
"x-go-name": "ID"
},
"name": {
"description": "Name is the pet's display name.",
"type": "string",
"x-go-name": "Name"
},
"tags": {
"description": "Tags categorise the pet.",
"type": "array",
"items": {
"type": "string"
},
"x-go-name": "Tags"
}
},
"x-go-package": "github.com/go-openapi/codescan/docs/examples/concepts/models"
}
Full source: docs/examples/concepts/models/testdata/model.json
A swagger:model that nothing else references appears in definitions only
when you scan with Options.ScanModels (the -m flag). See
When the scanner emits a type.
swagger:strfmt
swagger:strfmt <name> marks a named string type as a custom format. The type
does not become its own definition — instead, every field typed by it renders as
{type: string, format: <name>}.
// MAC is a hardware address rendered as a colon-separated hex string.
//
// swagger:strfmt mac
type MAC string
func (m MAC) MarshalText() ([]byte, error) { return []byte(m), nil }
func (m *MAC) UnmarshalText(b []byte) error { *m = MAC(b); return nil }
// Device exposes a strfmt-typed field: wherever MAC appears it renders inline
// as {type: string, format: mac}.
//
// swagger:model
type Device struct {
// Addr is the hardware address.
Addr MAC `json:"addr"`
}Full source: docs/examples/concepts/models/models.go
{
"description": "Device exposes a strfmt-typed field: wherever MAC appears it renders inline\nas {type: string, format: mac}.",
"type": "object",
"properties": {
"addr": {
"description": "Addr is the hardware address.",
"type": "string",
"format": "mac",
"x-go-name": "Addr"
}
},
"x-go-package": "github.com/go-openapi/codescan/docs/examples/concepts/models"
}
Full source: docs/examples/concepts/models/testdata/strfmt.json
Add swagger:model to the strfmt type to opt it into a first-class definition
({type: string, format: <name>}) that fields $ref instead of inlining — the
general swagger:model ⇒ definition + $ref rule.
swagger:enum
swagger:enum <name> collects the type’s const values. When a model field
references the type, the property carries the enum array and an
x-go-enum-desc extension built from the per-value doc comments. (The enum type
is reachable, and so emitted, only because a model field points at it.) A bare
swagger:enum on the type declaration works too — the name is inferred.
// Priority is the urgency level on a task.
//
// swagger:enum Priority
type Priority string
const (
// PriorityLow is for tasks that can wait.
PriorityLow Priority = "low"
// PriorityMedium is the default.
PriorityMedium Priority = "medium"
// PriorityHigh is for tasks that must run soon.
PriorityHigh Priority = "high"
)
// Task is a unit of work carrying an enum-typed field. Referencing Priority
// from a model is what makes the enum reachable, and so emitted.
//
// swagger:model
type Task struct {
// Priority is the task's urgency.
Priority Priority `json:"priority"`
}Full source: docs/examples/concepts/models/models.go
{
"description": "Task is a unit of work carrying an enum-typed field. Referencing Priority\nfrom a model is what makes the enum reachable, and so emitted.",
"type": "object",
"properties": {
"priority": {
"description": "Priority is the task's urgency.\nlow PriorityLow is for tasks that can wait.\nmedium PriorityMedium is the default.\nhigh PriorityHigh is for tasks that must run soon.",
"type": "string",
"enum": [
"low",
"medium",
"high"
],
"x-go-enum-desc": "low PriorityLow is for tasks that can wait.\nmedium PriorityMedium is the default.\nhigh PriorityHigh is for tasks that must run soon.",
"x-go-name": "Priority"
}
},
"x-go-package": "github.com/go-openapi/codescan/docs/examples/concepts/models"
}
Full source: docs/examples/concepts/models/testdata/enum.json
Here the values inline on the referencing field. Add swagger:model to the enum
type to make it a first-class definition (carrying the enum array) that fields
$ref — again the swagger:model ⇒ definition + $ref rule.
Enums have more to them than a string const block: iota and computed members,
what decides the emitted type / format, and the inline form parameters and
headers take. They get their own page —
Enumerations.
swagger:allOf
Embedding base types under swagger:allOf composes a schema. Each embedded base
becomes a $ref arm of the allOf; the struct’s own (non-embedded) fields form
a final inline arm. That last arm is inline rather than a $ref because those
fields are new to this type — they belong to no existing definition to point at.
Here Dog embeds two bases (Animal, Tagged) and adds breed, producing
three arms: two $refs and one inline object.
// Animal is one abstract base.
//
// swagger:model
type Animal struct {
// Kind discriminates the animal.
Kind string `json:"kind"`
}
// Tagged is a second reusable base.
//
// swagger:model
type Tagged struct {
// Tags label the resource.
Tags []string `json:"tags"`
}
// Dog composes two base models plus its own fields: each embedded base becomes
// a $ref arm of the allOf, and the struct's own (non-embedded) fields — which
// are new and cannot be a $ref — form the final inline arm.
//
// swagger:model
type Dog struct {
// swagger:allOf
Animal
// swagger:allOf
Tagged
// Breed is the dog's breed.
Breed string `json:"breed"`
}Full source: docs/examples/concepts/models/models.go
{
"description": "Dog composes two base models plus its own fields: each embedded base becomes\na $ref arm of the allOf, and the struct's own (non-embedded) fields — which\nare new and cannot be a $ref — form the final inline arm.",
"allOf": [
{
"$ref": "#/definitions/Animal"
},
{
"$ref": "#/definitions/Tagged"
},
{
"type": "object",
"properties": {
"breed": {
"description": "Breed is the dog's breed.",
"type": "string",
"x-go-name": "Breed"
}
}
}
],
"x-go-package": "github.com/go-openapi/codescan/docs/examples/concepts/models"
}
Full source: docs/examples/concepts/models/testdata/allof.json
When the base also declares a discriminator, this composition becomes a
Swagger 2.0 type hierarchy — see
Polymorphic models.
swagger:type
swagger:type <type> overrides the type codescan would infer. Here a [16]byte
field is published as a string.
// ULID is a 128-bit identifier stored as bytes but rendered as a string.
//
// swagger:type string
type ULID [16]byte
// Token carries a field whose inferred type is overridden, inline.
//
// swagger:model
type Token struct {
// ID renders as a string despite its [16]byte Go type.
ID ULID `json:"id"`
}
// RawID is a custom 16-byte identifier — an array under the hood, so left to
// itself a field of this type would render as an array of integers.
type RawID [16]byte
// Coupon overrides the type of a single field directly on the field doc — no
// wrapper-type annotation. Code publishes as a bare string while RawID is left
// untouched everywhere else it appears.
//
// swagger:model
type Coupon struct {
// Code is an opaque identifier published as a string.
//
// swagger:type string
Code RawID `json:"code"`
// Amount is the discount in cents.
Amount int64 `json:"amount"`
}Full source: docs/examples/concepts/models/models.go
{
"type": "object",
"title": "Token carries a field whose inferred type is overridden, inline.",
"properties": {
"id": {
"description": "ID renders as a string despite its [16]byte Go type.",
"type": "string",
"x-go-name": "ID"
}
},
"x-go-package": "github.com/go-openapi/codescan/docs/examples/concepts/models"
}
Full source: docs/examples/concepts/models/testdata/type.json
swagger:type is an inline directive: it renders the chosen type in place
and never emits a $ref. The value is a scalar type (string, integer,
number, boolean, object, or a Go builtin like int64), []T for an array
of an inlined type, inline to expand the field’s own Go type, or a known type
name to inline that type. array is deprecated in favour of inline / []T,
and file is rejected (use swagger:file). When combined with swagger:strfmt,
the type wins and the format is kept only if compatible — see the
reference.
The override also works on an individual field doc — no wrapper-type
annotation. Here Code is published as a string while its RawID type is left
untouched everywhere else:
// RawID is a custom 16-byte identifier — an array under the hood, so left to
// itself a field of this type would render as an array of integers.
type RawID [16]byte
// Coupon overrides the type of a single field directly on the field doc — no
// wrapper-type annotation. Code publishes as a bare string while RawID is left
// untouched everywhere else it appears.
//
// swagger:model
type Coupon struct {
// Code is an opaque identifier published as a string.
//
// swagger:type string
Code RawID `json:"code"`
// Amount is the discount in cents.
Amount int64 `json:"amount"`
}Full source: docs/examples/concepts/models/models.go
{
"description": "Coupon overrides the type of a single field directly on the field doc — no\nwrapper-type annotation. Code publishes as a bare string while RawID is left\nuntouched everywhere else it appears.",
"type": "object",
"properties": {
"amount": {
"description": "Amount is the discount in cents.",
"type": "integer",
"format": "int64",
"x-go-name": "Amount"
},
"code": {
"description": "Code is an opaque identifier published as a string.",
"type": "string",
"x-go-name": "Code"
}
},
"x-go-package": "github.com/go-openapi/codescan/docs/examples/concepts/models"
}
Full source: docs/examples/concepts/models/testdata/typefield.json
swagger:name
swagger:name <name> overrides the JSON property name a field or method
renders as. It works on a struct field (overriding the json: tag / Go
field name) and on an interface method. It is most useful on interface
methods, which publish one property per nullary method and cannot carry a
json tag: below, StructType() would default to structType, and the
annotation publishes it as jsonClass instead.
Note
swagger:name is the legacy annotation form. The
name: keyword is the
canonical, universal equivalent — it renames a property here exactly the
same way, and is the only form that also works on parameters and
response headers. Precedence: name: > swagger:name > json: tag > Go
field name.
// Car is exposed as a schema via its method set. Interface methods cannot carry
// a json tag, so by default each property takes the camelCased method name;
// swagger:name overrides that where the default is not what you want.
//
// swagger:model
type Car interface {
// Maker is the manufacturer. With no override the property is the
// camelCased method name, "maker".
Maker() string
// StructType is the polymorphic class. Without the override the property
// would be "structType"; swagger:name publishes it as "jsonClass".
//
// swagger:name jsonClass
StructType() string
}
// Account shows the universal name: keyword renaming model struct fields. The
// same keyword used on parameters and response headers also sets a property key
// here, winning over a json tag, the legacy swagger:name annotation, and the Go
// field name.
//
// swagger:model
type Account struct {
// Bal has no json tag; the keyword sets the property key directly.
//
// name: balance
Bal float64
// Currency carries both naming forms; the keyword wins over the
// legacy annotation and the json tag.
//
// name: currencyCode
// swagger:name legacyCurrency
Currency string `json:"currency"`
}Full source: docs/examples/concepts/models/models.go
{
"description": "Car is exposed as a schema via its method set. Interface methods cannot carry\na json tag, so by default each property takes the camelCased method name;",
"type": "object",
"properties": {
"jsonClass": {
"description": "StructType is the polymorphic class. Without the override the property\nwould be \"structType\"; swagger:name publishes it as \"jsonClass\".",
"type": "string",
"x-go-name": "StructType"
},
"maker": {
"description": "Maker is the manufacturer. With no override the property is the\ncamelCased method name, \"maker\".",
"type": "string",
"x-go-name": "Maker"
}
},
"x-go-package": "github.com/go-openapi/codescan/docs/examples/concepts/models"
}
Full source: docs/examples/concepts/models/testdata/name.json
The name: keyword does the same on a model property — and, being the universal
form, with the same syntax you would use on a parameter or header. Here it names
a tag-less field directly, and on a field that also carries a json: tag and a
legacy swagger:name, the keyword wins (name: > swagger:name > json: tag >
Go field name):
// Account shows the universal name: keyword renaming model struct fields. The
// same keyword used on parameters and response headers also sets a property key
// here, winning over a json tag, the legacy swagger:name annotation, and the Go
// field name.
//
// swagger:model
type Account struct {
// Bal has no json tag; the keyword sets the property key directly.
//
// name: balance
Bal float64
// Currency carries both naming forms; the keyword wins over the
// legacy annotation and the json tag.
//
// name: currencyCode
// swagger:name legacyCurrency
Currency string `json:"currency"`
}Full source: docs/examples/concepts/models/models.go
{
"description": "Account shows the universal name: keyword renaming model struct fields. The\nsame keyword used on parameters and response headers also sets a property key\nhere, winning over a json tag, the legacy swagger:name annotation, and the Go\nfield name.",
"type": "object",
"properties": {
"balance": {
"description": "Bal has no json tag; the keyword sets the property key directly.",
"type": "number",
"format": "double",
"x-go-name": "Bal"
},
"currencyCode": {
"description": "Currency carries both naming forms; the keyword wins over the\nlegacy annotation and the json tag.",
"type": "string",
"x-go-name": "Currency"
}
},
"x-go-package": "github.com/go-openapi/codescan/docs/examples/concepts/models"
}
Full source: docs/examples/concepts/models/testdata/namekeyword.json
swagger:ignore
swagger:ignore drops a declaration from the output. The scanner sees Secret,
classifies it, then excludes it — so it never reaches the definitions (a fact
the example’s TestIgnoreOmitsType asserts). It also works on a single struct
field — placed on the field’s doc comment, it drops just that property from
the model.
// Secret never reaches the spec.
//
// swagger:ignore
type Secret struct {
// Token is internal.
Token string `json:"token"`
}Full source: docs/examples/concepts/models/models.go
Decorating a $ref
When a field’s type resolves to a named model, the property is a $ref — and a
bare $ref cannot carry sibling keywords (a JSON Schema draft-4 rule). So a
field that is both a reference and decorated (a description, a vendor
extension, a default/example, a validation override) would lose its
decorations.
codescan avoids that by wrapping the $ref as a member of an allOf. The
property is then an ordinary schema object, free to carry the decorations
alongside the reference:
- the
descriptionand anyx-*extensions sit on the property itself; - a value override (
default,example) rides a secondallOfmember; requiredrides the parent model’srequiredlist.
// 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 that also carries a description and
// a vendor extension. A bare $ref cannot hold sibling keywords, so codescan
// wraps the reference as a member of an allOf — the property is then a normal
// schema that keeps the description and the x-* extension, and required goes to
// the parent. Nothing is dropped.
//
// swagger:model
type Person struct {
// Home is where the person lives.
//
// required: true
// extensions:
// x-ui-order: 3
Home Address `json:"home"`
}Full source: docs/examples/concepts/refoverride/refoverride.go
{
"description": "Person references Address through a field that also carries a description and\na vendor extension. A bare $ref cannot hold sibling keywords, so codescan\nwraps the reference as a member of an allOf — the property is then a normal\nschema that keeps the description and the x-* extension, and required goes to\nthe parent. Nothing is dropped.",
"type": "object",
"required": [
"home"
],
"properties": {
"home": {
"description": "Home is where the person lives.",
"allOf": [
{
"$ref": "#/definitions/Address"
}
],
"x-go-name": "Home",
"x-ui-order": 3
}
},
"x-go-package": "github.com/go-openapi/codescan/docs/examples/concepts/refoverride"
}
Full source: docs/examples/concepts/refoverride/testdata/refoverride.json
Nothing is dropped. The description-only case is the exception — it is governed
by the DescWithRef option (see
Descriptions beside a $ref) —
and a default/example on a $ref’d field is shown in
Examples & defaults.
Info
Same-name collisions. Two structs that share the same short name in
different packages stay distinct: codescan keys each by a compiler-unique
identity and qualifies the colliding ones with a package segment
(billing.Account / identity.Account → BillingAccount / IdentityAccount),
deterministically. Pin the names in your public contract with an explicit
swagger:model <Name>, and let auto-resolution handle the rest — see
Resolving $ref name conflicts.
What’s next
- Routes & operations — wire these models into paths, parameters and responses.
- Validations — constrain field values with keyword annotations.
- Shaping the output — alias handling,
$refvs inline, nullable pointers and more.