Building an API To List All Endpoints Exposed by Spring Boot
Tags: java, programming, softwaredevelopment, softwareengineering
Published: 2024-01-19 20:42:21

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](https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html).

> _"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](https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html)

The [`spring-boot-actuator`](https://github.com/spring-projects/spring-boot/tree/v2.4.1/spring-boot-project/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`](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.html).

This class is used by Spring Boot to execute every method annotated with [`@RequestMapping`](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html) 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

```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
        );
    }
}
```

#### Kotlin

```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
        )
    }
}
```

In both cases, I used the [`handlerMethods`](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.html#getHandlerMethods--) attribute, which stores a read-only map with all mappings and [HandlerMethod](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/method/HandlerMethod.html)'s. The mappings are the keys of the entries and are represented by [RequestMappingInfo](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/RequestMappingInfo.html) objects. Their [`toString()`](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/RequestMappingInfo.html#toString--) method returns all you need to reach the endpoint associated with a [HandlerMethod](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/method/HandlerMethod.html) object, specifically, the method annotated with `_@RequestMapping_`_._

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

```javascript
[
   "{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}"    
]
```

## 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](https://writech.run/blog/building-an-api-to-list-all-endpoints-exposed-by-spring-boot-645f1f64ebf3/)" appeared first on [Writech](https://writech.run)._