I solved this for my use case by using a Map to store 'sub' paths and passing all the requests to a generalized controller.
My use case needed a generic proxy app for multiple back-ends. Not too much different than what as you described a possible solution.
Source code -
https://github.com/savantly-net/mesh-gateway
Example -
@RestController
@RequestMapping(MeshGateway.PATH)
public class MeshGateway {
protected static final String PATH = "/gateway";
private static final Logger log = LoggerFactory.getLogger(MeshGateway.class);
private MeshGatewayConfig config;
public MeshGateway(MeshGatewayConfig config) {
this.config = config;
}
@GetMapping("/{child}/**")
public ResponseEntity<?> get(@PathVariable String child, ProxyExchange<byte[]> proxy) throws Exception {
log.debug("doing GET: {}", proxy.path());
return proxy.uri(getDestinationPath(child, proxy)).get();
}
@PostMapping("/{child}/**")
public ResponseEntity<?> post(@PathVariable String child, ProxyExchange<byte[]> proxy) throws Exception {
log.debug("doing GET: {}", proxy.path());
return proxy.uri(getDestinationPath(child, proxy)).post();
}
@PutMapping("/{child}/**")
public ResponseEntity<?> put(@PathVariable String child, ProxyExchange<byte[]> proxy) throws Exception {
log.debug("doing GET: {}", proxy.path());
return proxy.uri(getDestinationPath(child, proxy)).put();
}
@RequestMapping(path = "/{child}/**", method = RequestMethod.OPTIONS)
public ResponseEntity<?> options(@PathVariable String child, ProxyExchange<byte[]> proxy) throws Exception {
log.debug("doing GET: {}", proxy.path());
return proxy.uri(getDestinationPath(child, proxy)).options();
}
@RequestMapping(path = "/{child}/**", method = RequestMethod.PATCH)
public ResponseEntity<?> patch(@PathVariable String child, ProxyExchange<byte[]> proxy) throws Exception {
log.debug("doing GET: {}", proxy.path());
return proxy.uri(getDestinationPath(child, proxy)).patch();
}
@RequestMapping(path = "/{child}/**", method = RequestMethod.DELETE)
public ResponseEntity<?> delete(@PathVariable String child, ProxyExchange<byte[]> proxy) throws Exception {
log.debug("doing GET: {}", proxy.path());
return proxy.uri(getDestinationPath(child, proxy)).delete();
}
@RequestMapping(path = "/{child}/**", method = RequestMethod.HEAD)
public ResponseEntity<?> head(@PathVariable String child, ProxyExchange<byte[]> proxy) throws Exception {
log.debug("doing GET: {}", proxy.path());
return proxy.uri(getDestinationPath(child, proxy)).head();
}
private String getDestinationPath(String child, ProxyExchange<byte[]> proxy) {
String destination = this.config.getRoutes().get(child);
String path = proxy.path(String.format("%s/%s", PATH, child));
log.debug("with prefix removed: {}", path);
return String.format("%s%s", destination, path);
}
}