Skip to content

Support example tag on map[string]Struct fields#2181

Draft
rykpl wants to merge 1 commit into
swaggo:masterfrom
rykpl:feat/example-tag-map-struct-synthesis
Draft

Support example tag on map[string]Struct fields#2181
rykpl wants to merge 1 commit into
swaggo:masterfrom
rykpl:feat/example-tag-map-struct-synthesis

Conversation

@rykpl

@rykpl rykpl commented Jun 24, 2026

Copy link
Copy Markdown

Summary

Fields typed as map[string]SomeStruct have never been able to carry an example tag:

  • No tag — a correct additionalProperties: $ref schema is generated, but with no example, so Swagger UI renders an empty {} that tells the reader nothing about the value shape.
  • Any tag — the value reaches the key:value comma parser in defineTypeOfExample with arrayType="object", which cannot represent nested struct values and errors out (example value en should format: key:value, or ... is unsupported type ... on the recursive value side).

This PR makes the example tag work on these fields via two opt-in forms, both surfaced through the existing example struct tag. Open since 2019 (#327).

Changes

parser.go

  • defineTypeOfExample: when the map value type is itself an object (arrayType="object"), accept either

    • raw JSON — unmarshalled and used as the explicit example, or
    • a plain (non-JSON) string — returned as-is to act as a key-name hint for synthesis.

    Previously both paths errored.

  • New buildExampleFromRef: synthesises an example object from a $ref definition's properties — pulling each property's own Example, and for array properties wrapping a single-element slice (recursing into []SomeStruct item refs, or using the item example for []primitive). Guards against cycles in mutually-recursive type graphs.

field_parser.go

  • ComplementSchema: after the normal schema completion, if the field is an inline map[string]Struct (object schema with a $ref in AdditionalProperties) and the parsed example is a plain string, replace it with {<key>: <synthesised value>}. If nothing can be synthesised, the example is cleared rather than left as a dangling string.

Behaviour

Form 1 — Explicit JSON (used verbatim, same as example everywhere else):

Translations map[string]Message `json:"translations" example:"{\"en\":{\"text\":\"Hello\",\"locale\":\"en-US\"}}"`

Form 2 — Key name + auto-synthesis (value built from the struct's own field examples):

type Message struct {
    Text   string `json:"text"   example:"Hello"`
    Locale string `json:"locale" example:"en-US"`
}

Translations map[string]Message `json:"translations" example:"en"`

Generates:

"translations": {
  "example": {
    "en": { "text": "Hello", "locale": "en-US" }
  }
}

Backward compatibility

  • No implicit behaviour change — synthesis only fires when an example tag is present. Existing map[string]Struct fields with no tag are untouched (still render {}).
  • The previous hard parse error on an example tag for these fields is replaced by meaningful behaviour; no new errors are introduced.
  • map[string]string and swaggertype:"object,string" paths are unchanged — they never reach the arrayType="object" branch.

Known limitation

Named map type aliases are not supported by key-hint synthesis:

type LangMap map[string]Message            // named alias
Langs LangMap `json:"langs" example:"en"`   // synthesis does not fire

A named alias resolves to a $ref before ComplementSchema reaches the synthesis block (it takes the IsRefSchema path), so the inline-map guard never matches. This is a pre-existing architectural constraint affecting all field complementation on named map aliases, not specific to this change. Explicit JSON (Form 1) still works in this case.

Testing

  • parser_test.godefineTypeOfExample cases for map[string]Struct: raw-JSON acceptance and plain-string key-hint passthrough; buildExampleFromRef synthesis including nested arrays.
  • field_parser_test.go — end-to-end ComplementSchema cases covering Form 1, Form 2, and the no-tag (unaffected) path.

Related issues

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant