@@ -150,8 +150,7 @@ func generateExtraMethodInfo(resourceName string, extraMethod apibuilder.ExtraMe
150150 methodInfo .Summary = summary
151151 }
152152
153- // Check if path contains {id}
154- methodInfo .HasID = strings .Contains (extraMethod .Path , "{id}" )
153+ methodInfo .HasID = pathHasIDParam (extraMethod .Path )
155154
156155 // Parse path to extract resource path and sub-path
157156 pathParts := strings .Split (strings .Trim (extraMethod .Path , "/" ), "/" )
@@ -180,6 +179,21 @@ func generateExtraMethodInfo(resourceName string, extraMethod apibuilder.ExtraMe
180179 lastPart = pathParts [len (pathParts )- 2 ]
181180 }
182181 lastPart = cleanPathPart (lastPart )
182+ // If the last segment was a bare path parameter (e.g. {id}), cleanPathPart
183+ // strips it to "". Walk backwards to find the last meaningful segment so
184+ // that /tenants/metric_labels/{id}/ → "MetricLabels" and
185+ // /tenants/{tenant_id}/metric_label_values/{id}/ → "MetricLabelValues",
186+ // avoiding duplicate type/method names.
187+ if lastPart == "" {
188+ // Walk backwards but skip index 0 (the collection prefix, e.g. "s3keys")
189+ // to avoid generating names like "S3KeysS3keys".
190+ for i := len (pathParts ) - 2 ; i > 0 ; i -- {
191+ if c := cleanPathPart (pathParts [i ]); c != "" {
192+ lastPart = c
193+ break
194+ }
195+ }
196+ }
183197 action := toCamelCase (lastPart )
184198
185199 // Store base name without HTTP method suffix
@@ -669,6 +683,71 @@ func httpMethodToGoConstant(method string) string {
669683 }
670684}
671685
686+ // disambiguateExtraMethodNames assigns List/ById suffixes when the same base name+verb
687+ // would produce colliding Go methods (Go allows arity overloading only with identical return types).
688+ func disambiguateExtraMethodNames (methods []ExtraMethodInfo ) {
689+ groups := make (map [string ][]int )
690+ for i , m := range methods {
691+ key := m .Name + "_" + m .HTTPMethod
692+ groups [key ] = append (groups [key ], i )
693+ }
694+ for _ , indices := range groups {
695+ if len (indices ) <= 1 {
696+ continue
697+ }
698+ for _ , i := range indices {
699+ m := & methods [i ]
700+ oldName := m .Name
701+ switch {
702+ case m .ReturnsArray && ! m .HasID :
703+ m .Name += "List"
704+ case m .HasID :
705+ m .Name += "ById"
706+ default :
707+ m .Name += "Alt"
708+ }
709+ applyExtraMethodRename (m , oldName , m .Name )
710+ }
711+ }
712+ }
713+
714+ func applyExtraMethodRename (m * ExtraMethodInfo , oldName , newName string ) {
715+ if oldName == newName {
716+ return
717+ }
718+ m .BaseName = newName
719+ m .BodyTypeName = strings .Replace (m .BodyTypeName , oldName , newName , 1 )
720+ m .ResponseTypeName = strings .Replace (m .ResponseTypeName , oldName , newName , 1 )
721+ if m .ArrayItemType == oldName + "Item" {
722+ m .ArrayItemType = newName + "Item"
723+ }
724+ renameTypeRefs := func (typ string ) string {
725+ return strings .ReplaceAll (typ , oldName , newName )
726+ }
727+ for i := range m .BodyFields {
728+ m .BodyFields [i ].Type = renameTypeRefs (m .BodyFields [i ].Type )
729+ }
730+ for i := range m .ResponseFields {
731+ m .ResponseFields [i ].Type = renameTypeRefs (m .ResponseFields [i ].Type )
732+ }
733+ for _ , nt := range m .NestedTypes {
734+ nt .Name = strings .Replace (nt .Name , oldName , newName , 1 )
735+ for i := range nt .Fields {
736+ nt .Fields [i ].Type = renameTypeRefs (nt .Fields [i ].Type )
737+ }
738+ }
739+ }
740+
741+ // pathHasIDParam reports whether the path has a /{id}/ path parameter segment.
742+ func pathHasIDParam (path string ) bool {
743+ for _ , part := range strings .Split (strings .Trim (path , "/" ), "/" ) {
744+ if part == "{id}" {
745+ return true
746+ }
747+ }
748+ return false
749+ }
750+
672751// cleanPathPart removes {id} and other template variables from path part
673752func cleanPathPart (part string ) string {
674753 // Remove template variables like {id}, {name}, etc.
@@ -1519,6 +1598,8 @@ func main() {
15191598 fmt .Printf (" ✅ Generated extra method: %s\n " , extraMethodInfo .Name )
15201599 }
15211600
1601+ disambiguateExtraMethodNames (resourceData .ExtraMethods )
1602+
15221603 // Sort extra methods by name+method for deterministic output
15231604 sort .Slice (resourceData .ExtraMethods , func (i , j int ) bool {
15241605 iKey := resourceData .ExtraMethods [i ].Name + "_" + resourceData .ExtraMethods [i ].HTTPMethod
0 commit comments