I'm using spring doc open api in my spring boot project. In my rest controller I have 2 endpoints that are identical and only differ in params and the content of requestbody. Example:
@PostMapping(value = "/v1/types", params = "type=typeA)
...
@PostMapping(value = "/v1/types", params = "type=typeB)
Due OpenAPI Spec the endpoint should be unique and params are not considered as part of path. So swagger ui shows only one endpoint, I guess the first one in alphabetical order.
In my case my frontend team needs to know which endpoints to use in my api. So, I find the alternative from actuator the /mappings endpoint, that shows every endpoint in my project, extactly what I need.
My problem is that I need to add some description for each endpoint to describe which objects are required and what exactly the endpoint does.
Is there any way to add some kind of description under the endpoints listed in /actuator/mappings?
FYI: Spring Boot 3.3.0
Itried a lot with Swagger API, like adding several information to the endpoints, like with @Operation, @APIResponses or @Parameter annotations, but it doesn't help to show the same endpoint with different params.
I looked after the official spring boot actuator documentation, but there is no information about it.
You can make use of spring boot actuator like below,
Add dependency in your pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Create the Custom Endpoint
@Component
@Endpoint(id = "custommappings")
public class CustomMappingsEndpoint {
private final ApplicationContext applicationContext;
@Autowired
public CustomMappingsEndpoint(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@ReadOperation
public Map<String, Object> customMappings() {
Map<String, Object> mappings = new HashMap<>();
Map<String, RequestMappingHandlerMapping> allRequestMappings = applicationContext
.getBeansOfType(RequestMappingHandlerMapping.class);
for (RequestMappingHandlerMapping handlerMapping : allRequestMappings.values()) {
Map<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping.getHandlerMethods();
for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) {
RequestMappingInfo requestMappingInfo = entry.getKey();
HandlerMethod handlerMethod = entry.getValue();
// Extract path from PathPatternsRequestCondition
PathPatternsRequestCondition pathPatternsCondition = requestMappingInfo.getPathPatternsCondition();
Set<String> patterns = pathPatternsCondition != null ? pathPatternsCondition.getPatternValues() : null;
if (patterns != null && !patterns.isEmpty()) {
if (isExcludedPath(patterns.iterator().next())) {
continue; // Skip this path
}
}
Map<String, Object> endpointInfo = new HashMap<>();
endpointInfo.put("path", patterns.iterator().next());
endpointInfo.put("methods",
requestMappingInfo.getMethodsCondition() != null
? requestMappingInfo.getMethodsCondition().getMethods()
: "unknown");
endpointInfo.put("params",
requestMappingInfo.getParamsCondition() != null
? requestMappingInfo.getParamsCondition().getExpressions()
: "unknown");
endpointInfo.put("description", handlerMethod.getMethod().getName());
mappings.put(handlerMethod.getMethod().getName(), endpointInfo);
}
}
return mappings;
}
private boolean isExcludedPath(String path) {
// Define paths to exclude
return path.startsWith("/v3/api-docs") || path.startsWith("/error") || path.startsWith("/swagger-ui.html")
|| path.startsWith("/v3/api-docs.yaml");
// Add more paths as needed
}
Expose custom endpoint in your application.properties
management.endpoints.web.exposure.include=custommappings
Use below URL to get information about endpoint,
http://server:port/context-path/actuator/custommappings
The output:
{"method1":{"path":"/v1/types","methods":["POST"],"description":"method1","params":[{"name":"type","value":"typeA","negated":false}]},"method2":{"path":"/v1/types","methods":["POST"],"description":"method2","params":[{"name":"type","value":"typeB","negated":false}]},"method3":{"path":"/v1/getTypes","methods":["GET"],"description":"method3","params":[]}}