Spring Boot Actuator with Custom Endpoints
?? Saral Saxena ??????
?11K+ Followers | Linkedin Top Voice || Associate Director || 15+ Years in Java, Microservices, Kafka, Spring Boot, Cloud Technologies (AWS, GCP) | Agile , K8s ,DevOps & CI/CD Expert
Spring Boot Actuator is a sub component of Spring Boot. By default, Spring Actuator includes a series of endpoints that we can use to monitor and interact with our Spring application. Since these endpoints are predefined, sometimes we need to be able to retrieve information specific to our implementation to aid with the management of our application.
Endpoint Class
For the ‘Hello World’ series of endpoints that we will create throughout this article, we will use a single class HelloWorldEndpoint to contain the logic.We need to annotate this class with @Endpoint(id = ‘helloworld’). This tells Spring that we want to add a custom Spring Actuator endpoint with URI /helloworld and we will also manage this endpoint by using it’s id helloworld.
@Endpoint(id = "helloworld")
public class HelloWorldEndpoint {
}
Bean Configuration
Secondly, we must make our Endpoint class a Spring Bean.
In order to do this, lets create a configuration class to handle all the endpoint beans. Currently, we will only have one, but if we had multiple endpoints to manage this would be a nice configuration class to have!
In order to tell Spring the type of the class, we will annotate this class with the @Configuration annotation.
In our configuration class, create a method that returns an instance of our HelloWorldEndpoint class and annotate the method with @Bean.
@Configuration
public class CustomActuatorConfiguration {
@Bean
public HelloWorldEndpoint helloWorldEndpoint() {
return new HelloWorldEndpoint();
}
}
Endpoint Property
Lastly, before any of the endpoints we define in our HelloWorldEndpoint class are accessible we must tell Spring to expose our endpoint from its properties.
The property to include actuator endpoints is management.endpoints.web.exposure.include. In order for us to include our custom endpoint, we must add the id that we defined in our HelloWorldEndpoint class. For this example, we should include helloworld.
management.endpoints.web.exposure.include=helloworld
Hello World’ Custom Endpoint
Our first endpoint will return the String ‘Hello World’. So, let’s get this set up now.
public String helloWorld() { return "Hello World"; }
In order to expose a Spring Actuator endpoint to a HTTP GET request, we will need to annotate our method with the @ReadOperation annotation.
@ReadOperation public String helloWorld() { return "Hello World"; }
We can now rerun our application and hit our new endpoint:
> curl 'https://localhost:8080/actuator/helloworld' Hello World
Parameterising our Custom Endpoint
Query Parameter
The easiest way to have our endpoint accept data is by adding it as a parameter to our method. Method parameters will get mapped to a query parameter of that name in the URL and they will be required.
Currently, Spring will only accept basic types as a parameter. So for example, parameters can be a String, int, boolean but not an object like a list.
For example, by adding String name to this method, we are telling Spring to expect a query parameter named name.
@ReadOperation public String helloName(String name) { return "Hello " + name; }
We can now rerun our application and hit the endpoint:
> curl 'https://localhost:8080/actuator/helloworld?name=Jamie' Hello Jamie
Path Variable
If we wanted our parameters to be path variables instead of a query parameter, we need to annotate each method parameter with @Selector.
@ReadOperation public String helloNameSelector(@Selector String name) { return "Hello " + name; }
We can now rerun our application and hit the endpoint:
> curl 'https://localhost:8080/actuator/helloworld/Alex' Hello Alex
POST Requests
So far we’ve only added endpoints that work with HTTP GET. We can also expose endpoints via HTTP POST. To do this, instead of annotating our method with @ReadOperation we will use @WriteOperation instead.
By using HTTP POST we also have the added ability of using the HTTP Body to retrieve information into our endpoint. The method parameters on a method annotated with @WriteOperation will automatically be retrieved from the HTTP Body.
The same rules apply for values in the body request as they do in the previous examples, they can only be of simple types and not be an object.
@WriteOperation public String helloNameBody(String name) { return "Hello " + name; }
We can now rerun our application and hit the endpoint:
> curl --location --request POST 'https://localhost:8080/actuator/helloworld' \ > --header 'Content-Type: application/json' \ > --data-raw '{ > "name": "Albie" > }' Hello Albie
DELETE Requests
So far we’ve seen @ReadOperation for HTTP GET requests, @WriteOperation for HTTP POST requests and lastly we have @DeleteOperation for HTTP DELETE requests.
Just like the @ReadOperation endpoints, we can have input via query parameter and via path variables.
Instead of ‘Hello {name}’, for the DELETE endpoints we will return ‘Goodbye {name}’.
@DeleteOperation public String goodbyeNameParam(String name) { return "Goodbye " + name; } @DeleteOperation public String goodbyeNameSelector(@Selector String name) { return "Goodbye " + name; }
For the final time, we can now rerun our application and hit the endpoints:
> curl --location --request DELETE 'https://localhost:8080/actuator/helloworld?name=Jamie' Goodbye Jamie > curl --location --request DELETE 'https://localhost:8080/actuator/helloworld/Alex' Goodbye Alex