buildRouteURL generates a URL from route segments and parameters. This shared helper is used by both Route.URL() and DefaultRes.getLocationFromRoute() to ensure consistent URL generation behavior across APIs. Parameter resolution uses a deterministic three-step lookup: 1. Exact key match on segment
(route *Route, params Map)
| 102 | // 2. Case-insensitive fallback picking the lexicographically-smallest matching key (when !caseSensitive) |
| 103 | // 3. Greedy parameter fallback for wildcard (*) and plus (+) parameters |
| 104 | func buildRouteURL(route *Route, params Map) (string, error) { |
| 105 | if len(route.routeParser.segs) == 0 { |
| 106 | return route.Path, nil |
| 107 | } |
| 108 | |
| 109 | buf := bytebufferpool.Get() |
| 110 | defer bytebufferpool.Put(buf) |
| 111 | |
| 112 | for _, segment := range route.routeParser.segs { |
| 113 | if !segment.IsParam { |
| 114 | _, err := buf.WriteString(segment.Const) |
| 115 | if err != nil { |
| 116 | return "", fmt.Errorf("failed to write string: %w", err) |
| 117 | } |
| 118 | continue |
| 119 | } |
| 120 | |
| 121 | var ( |
| 122 | val any |
| 123 | found bool |
| 124 | ) |
| 125 | |
| 126 | // Prefer an exact parameter name match |
| 127 | if val, found = params[segment.ParamName]; !found && !route.caseSensitive { |
| 128 | // Fall back to a case-insensitive match using a deterministic winner |
| 129 | var matchedKey string |
| 130 | foundMatch := false |
| 131 | for key := range params { |
| 132 | if utils.EqualFold(key, segment.ParamName) && (!foundMatch || key < matchedKey) { |
| 133 | matchedKey = key |
| 134 | foundMatch = true |
| 135 | } |
| 136 | } |
| 137 | if foundMatch { |
| 138 | val = params[matchedKey] |
| 139 | found = true |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | // For greedy parameters, fall back to generic greedy keys |
| 144 | if !found && segment.IsGreedy { |
| 145 | for _, greedyKey := range preferredGreedyParameters(segment.ParamName) { |
| 146 | if val, found = params[greedyKey]; found { |
| 147 | break |
| 148 | } |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | if found { |
| 153 | _, err := buf.WriteString(utils.ToString(val)) |
| 154 | if err != nil { |
| 155 | return "", fmt.Errorf("failed to write string: %w", err) |
| 156 | } |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | return buf.String(), nil |
| 161 | } |
no test coverage detected