3232import java .util .LinkedHashSet ;
3333import java .util .List ;
3434import java .util .Locale ;
35+ import java .util .Map ;
3536import java .util .Objects ;
3637import java .util .Set ;
3738import java .util .Vector ;
5152import org .springframework .core .Conventions ;
5253import org .springframework .core .MethodParameter ;
5354import org .springframework .core .ParameterizedTypeReference ;
55+ import org .springframework .http .HttpEntity ;
5456import org .springframework .http .HttpHeaders ;
5557import org .springframework .http .RequestEntity ;
5658import org .springframework .http .RequestEntity .BodyBuilder ;
@@ -142,6 +144,10 @@ public class ProxyExchange<T> {
142144
143145 private @ Nullable URI uri ;
144146
147+ private @ Nullable String uriTemplate ;
148+
149+ private @ Nullable Map <String , ?> uriVariables ;
150+
145151 private RestTemplate rest ;
146152
147153 private @ Nullable Object body ;
@@ -231,6 +237,8 @@ public ProxyExchange<T> excluded(String... names) {
231237 */
232238 public ProxyExchange <T > uri (URI uri ) {
233239 this .uri = uri ;
240+ this .uriTemplate = null ;
241+ this .uriVariables = null ;
234242 return this ;
235243 }
236244
@@ -248,6 +256,21 @@ public ProxyExchange<T> uri(String uri) {
248256 }
249257 }
250258
259+ /**
260+ * Sets the uri for the backend call using a URI template with variables. When a
261+ * template is provided, the downstream {@link RestTemplate} call preserves the
262+ * template pattern for observability (e.g. Micrometer URI tags).
263+ * @param uriTemplate the URI template (e.g. {@code "http://service/foos/{id}"})
264+ * @param uriVariables the variables to expand in the template
265+ * @return this for convenience
266+ */
267+ public ProxyExchange <T > uri (String uriTemplate , Map <String , ?> uriVariables ) {
268+ this .uriTemplate = uriTemplate ;
269+ this .uriVariables = uriVariables ;
270+ this .uri = rest .getUriTemplateHandler ().expand (uriTemplate , uriVariables );
271+ return this ;
272+ }
273+
251274 public @ Nullable String path () {
252275 return (String ) this .webRequest .getAttribute (HandlerMapping .PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE ,
253276 WebRequest .SCOPE_REQUEST );
@@ -383,6 +406,11 @@ private ResponseEntity<T> exchange(RequestEntity<?> requestEntity) {
383406 if (type instanceof TypeVariable || type instanceof WildcardType ) {
384407 type = Object .class ;
385408 }
409+ if (this .uriTemplate != null && this .uriVariables != null ) {
410+ return rest .exchange (this .uriTemplate , Objects .requireNonNull (requestEntity .getMethod ()),
411+ new HttpEntity <>(requestEntity .getBody (), requestEntity .getHeaders ()),
412+ ParameterizedTypeReference .forType (type ), this .uriVariables );
413+ }
386414 return rest .exchange (requestEntity , ParameterizedTypeReference .forType (type ));
387415 }
388416
0 commit comments