Skip to content

Commit 323d24f

Browse files
fredbiclaude
andauthored
doc(mixin): clarify precedence rules and document limitations (#196)
Rewrite the Mixin godoc into three labeled sections: * Argument order and precedence, with a worked host example showing that the primary always wins on collision and that mixins are listed in decreasing priority order. * What gets merged, enumerating exactly which fields are filled from empty primaries, which are merged entry-by-entry with collision warnings, and which are unioned silently (schemes, consumes, produces). * Notes and limitations, with cross-references to the new goswagger.io FAQ entries on YAML anchor preservation and on output ordering. This is a documentation-only change addressing user-confusion issues in go-swagger/go-swagger: * go-swagger/go-swagger#1823 (precedence) * go-swagger/go-swagger#1928 (YAML anchors not preserved) * go-swagger/go-swagger#2130 (output is alphabetically ordered; this is an architectural constraint inherited from the underlying spec model, not fixable here) Companion FAQ entries land in go-swagger/go-swagger docs/faq/faq_swagger.md and the canonical reference moves into docs/usage/mixin.md. Signed-off-by: Frederic BIDON <fredbi@yahoo.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent cff0ae2 commit 323d24f

2 files changed

Lines changed: 52 additions & 21 deletions

File tree

‎.gitignore‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33
.idea
44
.env
55
.mcp.json
6+
go.work.sum
7+
.worktrees

‎mixin.go‎

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,37 +11,66 @@ import (
1111
"github.com/go-openapi/spec"
1212
)
1313

14-
// Mixin modifies the primary swagger spec by adding the paths and
15-
// definitions from the mixin specs. Top level parameters and
16-
// responses from the mixins are also carried over. Operation id
17-
// collisions are avoided by appending "Mixin<N>" but only if
18-
// needed.
14+
// Mixin merges one or more Swagger 2.0 documents into a primary document.
1915
//
20-
// The following parts of primary are subject to merge, filling empty details
16+
// # Argument order and precedence
2117
//
22-
// - Info
18+
// The first argument is the primary spec, which Mixin modifies in place.
19+
// Subsequent arguments are mixins, listed in decreasing order of priority.
20+
// On any collision, the primary always wins; among mixins, the earliest one
21+
// wins.
22+
//
23+
// Example: given a primary spec with host "a.example.com" and a mixin with
24+
// host "b.example.com", the merged result keeps "a.example.com" (primary
25+
// wins, the mixin value is dropped). Given a primary without a host and a
26+
// mixin with host "b.example.com", the merged result uses "b.example.com"
27+
// (the mixin fills in the empty field on the primary).
28+
//
29+
// # What gets merged
30+
//
31+
// Top-level scalar fields on the primary are filled from the first mixin
32+
// that provides them, but only if the primary's value is the zero value:
33+
//
34+
// - Info (including the nested Contact and License)
2335
// - BasePath
2436
// - Host
2537
// - ExternalDocs
2638
//
27-
// Consider calling [FixEmptyResponseDescriptions]() on the modified primary
28-
// if you read them from storage and they are valid to start with.
39+
// Map and slice fields are merged entry by entry. This covers:
40+
//
41+
// - paths, definitions, parameters, responses
42+
// - securityDefinitions, security, tags
43+
// - top-level and Info extensions
44+
//
45+
// Duplicate keys (or equal security requirements, or equal tag names) are
46+
// skipped with a warning; warnings are returned as a slice and intended to
47+
// be inspected by the caller (e.g. compared to an expected collision count
48+
// in build scripts).
49+
//
50+
// Schemes, consumes and produces are merged as the union of distinct
51+
// values. Duplicates there are silently dropped, no warning is emitted.
52+
//
53+
// Operation id collisions are auto-resolved by appending "Mixin<N>" to the
54+
// mixin operation id (N is the mixin index), so the merged spec keeps
55+
// unique operation ids.
56+
//
57+
// # Notes and limitations
2958
//
30-
// Entries in "paths", "definitions", "parameters" and "responses" are
31-
// added to the primary in the order of the given mixins. If the entry
32-
// already exists in primary it is skipped with a warning message.
59+
// Consider calling [FixEmptyResponseDescriptions] on the modified primary
60+
// if you read responses from storage and they are valid to start with.
3361
//
34-
// The count of skipped entries (from collisions) is returned so any
35-
// deviation from the number expected can flag a warning in your build
36-
// scripts. Carefully review the collisions before accepting them;
37-
// consider renaming things if possible.
62+
// No key normalization takes place. Ensure paths, type names, etc. are
63+
// canonical if your downstream tools rely on normalized forms.
3864
//
39-
// No key normalization takes place (paths, type defs,
40-
// etc). Ensure they are canonical if your downstream tools do
41-
// key normalization of any form.
65+
// YAML anchors (& / *) are resolved by the YAML parser before Mixin sees
66+
// the document, so they are not preserved in the merged output, and they
67+
// cannot be shared across input files. Use $ref for cross-file reuse. See
68+
// https://goswagger.io/go-swagger/faq/faq_swagger/#does-swagger-mixin-preserve-yaml-anchors
4269
//
43-
// Merging schemes ([http], https), and consumers/producers do not account for
44-
// collisions.
70+
// The order of paths and definitions in the merged output is alphabetical:
71+
// the underlying spec model stores them as Go maps, which serialize with
72+
// sorted keys. Source-file order is not preserved. See
73+
// https://goswagger.io/go-swagger/faq/faq_swagger/#can-i-control-the-path-or-operation-order-in-swagger-mixin-output
4574
func Mixin(primary *spec.Swagger, mixins ...*spec.Swagger) []string {
4675
skipped := make([]string, 0, len(mixins))
4776
opIDs := getOpIDs(primary)

0 commit comments

Comments
 (0)