I’ve been using webflux in Spring Boot 3.2.x and I’ve implemented a custom actuator endpoint like this:
@Component
@RestControllerEndpoint(id = "api", enableByDefault = true)
class ApiProxyEndpoint {
@Value("${management.endpoints.web.base-path}")
lateinit var managementPath: String
@Autowired
lateinit var webHandler: WebHandler
@RequestMapping("**") // Match all path segments under <management-path>/api/ until the end of the path
fun apiProxyEndpoint(exchange: ServerWebExchange): Mono<Void> {
val originalPath = exchange.request.path.toString()
val apiPathWithoutManagementPath = originalPath.substringAfter(managementPath)
val updatedRequest = exchange.request.mutate().contextPath("/").path(apiPathWithoutManagementPath).header("X-Api-RootPath" managementPath).build()
val updatedExchange = exchange.mutate().request(updatedRequest).build()
return webHandler.handle(updatedExchange)
}
}
The reason for doing this is that I want to expose the hal-browser as an actuator endpoint (so that I can browse the API from using the hal-browser from the actuator). What’s happening is that when the hal-browser calls a URI, by calling the “api” endpoint in actuator, and the request is then “forwarded”/proxied to the actual api endpoint (not behind actuator). So the code above acts as a proxy, just forwarding all requests made to “api” to somewhere else.
This has worked great for several years, but since Spring Boot 3.3.0, the RestControllerEndpoint
has been deprecated and I can’t find a way to replace it. I’ve tried this:
@Component
@WebEndpoint(id = "api", enableByDefault = true)
class ApiProxyEndpoint {
@Value("${management.endpoints.web.base-path}")
lateinit var managementPath: String
@Autowired
lateinit var webHandler: WebHandler
@WriteOperation
@ReadOperation
@DeleteOperation
fun apiProxyEndpoint(exchange: ServerWebExchange): Mono<Void> {
val originalPath = exchange.request.path.toString()
val apiPathWithoutManagementPath = originalPath.substringAfter(managementPath)
val updatedRequest = exchange.request.mutate().contextPath("/").path(apiPathWithoutManagementPath).header("X-Api-RootPath" managementPath).build()
val updatedExchange = exchange.mutate().request(updatedRequest).build()
return webHandler.handle(updatedExchange)
}
}
but this doesn’t work. The example above will show me this error in the HAL browser:
{
"timestamp": "2024-06-12T10:23:17.366+00:00",
"status": 400,
"error": "Bad Request",
"requestId": "efc7c7b9-4",
"message": "Missing parameters: exchange"
}
How can I achieve the same thing (i.e. proxying) in Spring Boot 3.3.0 without using the deprecated RestControllerEndpoint
?