DEV Community

Cover image for Building an API To List All Endpoints Exposed by Spring Boot
Antonello Zanini for Writech

Posted on • Updated on

Building an API To List All Endpoints Exposed by Spring Boot

Working with backends, I learned how you can easily lose sight of what is going on or what is currently deployed. This might become a problem, especially when dealing with production environments.

There are many libraries to tackle this question, and I personally recommend Spring Boot Actuator.

"Spring Boot includes a number of additional features to help you monitor and manage your application when you push it to production. You can choose to manage and monitor your application by using HTTP endpoints or with JMX. Auditing, health, and metrics gathering can also be automatically applied to your application."β€Šβ€”β€ŠSpring Documentation

The spring-boot-actuator module provides all of the aforementioned Spring Boot's production-ready features to help you monitor and manage your application.

However, the goal of this tutorial is not to show you how to harness the Spring Boot Actuator. In fact, for simple applications, a single monitoring API should be enough.

Based on my experience, the first and most important thing you can lose track of is the list of all exposed endpoints. There might be APIs you do not remember or use that are still online and potentially available to anyone. This should be avoided for security reasons, especially if these APIs are deprecated.

Let's see how to define a custom API returning a list of all endpoints exposed using the Spring Boot application.

Building the API

Looking online for a way to retrieve all deployed endpoints in a Spring Boot application, I discovered the existence of RequestMappingHandlerMapping.

This class is used by Spring Boot to execute every method annotated with @RequestMapping and contain a list of all of them, specifically, a list of all exposed endpoints by your application.

This is why implementing such an API is easier than you may think. This can be achieved as follows:

Java

@RestController
@RequestMapping("/monitoring/")
public class MonitoringController {
    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    @GetMapping("endpoints")
    public ResponseEntity<List<String>> getEndpoints() {
        return new ResponseEntity<>(
                requestMappingHandlerMapping
                        .getHandlerMethods()
                        .keySet()
                        .stream()
                        .map(RequestMappingInfo::toString)
                        .collect(Collectors.toList()),
                HttpStatus.OK
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

Kotlin

@RestController
@RequestMapping("/monitoring/")
class MonitoringController {
    @Autowired
    private lateinit var requestMappingHandlerMapping : RequestMappingHandlerMapping

    @GetMapping("endpoints")
    fun getEndpoints() : ResponseEntity<List<String>> {
        return ResponseEntity(
            requestMappingHandlerMapping
                .handlerMethods
                .map {
                    it.key.toString()
                },
            HttpStatus.OK
        )
    }
}
Enter fullscreen mode Exit fullscreen mode

In both cases, I used the handlerMethods attribute, which stores a read-only map with all mappings and HandlerMethod's. The mappings are the keys of the entries and are represented by RequestMappingInfo objects. Their toString() method returns all you need to reach the endpoint associated with a HandlerMethod object, specifically, the method annotated with _@RequestMapping_.

This is what an example of a response from this API looks like:

[
   "{GET /monitoring/endpoints}",      
   "{GET /v1/genres}",    
   "{GET /v1/genres/{id}}",
   "{POST /dex/v1/genres}", 
   "{PUT /v1/genres/{id}}",
   "{DELETE /v1/genres/{id}}",     
   "{PATCH /v1/genres/{id}}", 
   "{GET /v1/books}",    
   "{GET /v1/books/{id}}",
   "{POST /dex/v1/books}", 
   "{PUT /v1/books/{id}}",
   "{DELETE /v1/books/{id}}",     
   "{PATCH /v1/books/{id}}", 
   "{GET /v1/authors}",    
   "{GET /v1/authors/{id}}",
   "{POST /dex/v1/authors}", 
   "{PUT /v1/authors/{id}}",
   "{DELETE /v1/authors/{id}}",     
   "{PATCH /v1/authors/{id}}", 
   "{GET /v1/authors/{id}/books}"    
]
Enter fullscreen mode Exit fullscreen mode

Conclusion

Getting lost in the complexity or vastness of your backend is common. This is exactly why you should protect yourself by adding some monitoring tools. As I have shown, implementing an API to list all endpoints is not complex, and for simple systems, it may be enough.

Thanks for reading! I hope that you found this article helpful.


The post "Building an API To List All Endpoints Exposed by Spring Boot" appeared first on Writech.

Top comments (0)