How to output all endpoints exposed by Spring - java

I'd like to have a way how to expose all endpoints that exposed by my Spring application. Is there a simple way to check, for each #profile which are exposed?
Example:
GET /api/resource
GET /api/resource/list
POST /api/resource
PUT /api/resource
In the past, I have used a web application made in Laravel, and they had a simple cli method for checking the exposed methods.

I assume based on how the questions is worded that you are not using Spring Boot, if you were, the actuator mappings endpoint does this for you, but your answer lies in how the mappings endpoint is build in actuator. There is a RequestMappingHandlerMapping object you leverage.

In this scenario you can use two approaches:
Spring Boot Actuator feature. Your endpoints of application will be available at http://host/actuator/mappings
Swagger library can also be used to list all endpoints of a REST API

The best solution is to use Spring boot actuator and hit the endpoint /actuator/mappings to get all the endpoints.
But if you can't use actuator or can't add it as dependency you can retrieve all the endpoints programmatically the mapping handlers, Spring get shipped with three implementations of this interface (HandlerMapping):
RequestMappingHandlerMapping: which is responsible for endpoints that annotated with #RequestMapping and its variants #GetMapping, #PostMapping .. etc
BeanNameUrlHandlerMapping: as the name suggest it will resolve the endpoint(URL) directly to a bean in the application context. for example if you hit the endpoint /resource it will look for a bean with the name /resource.
RouterFunctionMapping: it will scan the application context for RouterFunction beans and dispatch the request to that function.
Anyways, to answer your question you can autowire the bean RequestMappingHandlerMapping and print out all the handler methods. Something similar to this:
#Autowired
RequestMappingHandlerMapping requestMappingHandlerMapping;
#PostConstruct
public void printEnpoints() {
requestMappingHandlerMapping.getHandlerMethods().forEach((k,v) -> System.out.println(k + " : "+ v));
}

Related

How to disable springSecurityFilterChain in test case?

Hi I have a spring project that has spring security to authenticate users using OAUTH provider, and I have to use Spring Cloud Contract to build up a mock server for consumer testing.
repo: https://github.com/Isaacwhyuenac/spring-cloud-contract-poc/blob/main/order-service/src/test/java/com/example/producer/BaseClass.java
When I run ./gradlew clean :order-service:contractTest. The following error is thrown
delegate cannot be null. Ensure a Bean with the name springSecurityFilterChain implementing Filter is present or inject the Filter to be used.
java.lang.IllegalStateException: delegate cannot be null. Ensure a Bean with the name springSecurityFilterChain implementing Filter is present or inject the Filter to be used.
If you look at my SecurityConfig
https://github.com/Isaacwhyuenac/spring-cloud-contract-poc/blob/main/order-service/src/main/java/com/example/producer/config/SecurityConfig.java
The security filter is already setup. So, how to resolve this error and have my contractTest running properly??
There are some issues on the BaseClass.
If you are using the latest Spring Boot, use #SpringBootTest is enough. No need the #ExtendedWith
Use a Mock env, set webEnvironment = Mock
If you decided to use RestAssuredMockMvc, you should use this mockMvc instead of the standard MockMVC in your tests.
The Mockito.reset in cleanup is no need at all.
In a WebMvc project, exclude the UserDetailsServiceAutoConfiguration and SecurityAutoConfiguration in your test context, check my example.
In a WebFlux project, just exclude ReactiveUserDetailsServiceAutoConfiguration and ReactiveSecurityAutoConfiguration and ReactiveOAuth2ResourceServerAutoConfiguration(if oauth2 resource server is enabled.) on your testing codes.
#SpringBootTest
#ImportAutoConfiguration(exclude = {ReactiveUserDetailsServiceAutoConfiguration.class, ReactiveSecurityAutoConfiguration.class})
class YourTest{
}
Or test web controller.
#WebFluxTest(controller=YourController.calss, excludeAutoConfigurations = {ReactiveUserDetailsServiceAutoConfiguration.class, ReactiveSecurityAutoConfiguration.class})
class YourTest{
}
I have created a simple Microservice sample several years ago, which used Spring Cloud Contract and Pact to implement the CDC pattern in the API testing and verify, check spring-microservice-sample.

Spring Boot Actuator - Custom Endpoints

I am using Spring Boot Actuator module in my project which exposes REST endpoint URLs to monitor & manage application usages in production environment, without coding & configuration for any of them.
By default, only /health and /info endpoints are exposed.
I am customising the endpoints via application.properties file as per my use case.
application.properties.
#To expose all endpoints
management.endpoints.web.exposure.include=*
#To expose only selected endpoints
management.endpoints.jmx.exposure.include=health,info,env,beans
I want to understand, where exactly does Spring Boot create actual endpoints for /health and /info and how does it expose them over HTTP?
Thanks #Puce and #MarkBramnik for helping me out with the reference docs & code repository.
I wanted to understand how the endpoints were working and how they were exposed over HTTP, so that I could create custom endpoints to leverage in my application.
One of the great features of Spring Framework is that it’s very easy to extend, and I was able to achieve the same.
To create a custom actuator endpoints, Use #Endpoint annotation on a class. Then leverage #ReadOperation / #WriteOperation / #DeleteOperation annotations on the methods to expose them as actuator endpoint bean as needed.
Reference Doc : Implementing Custom Endpoints
Reference Example :
#Endpoint(id="custom_endpoint")
#Component
public class MyCustomEndpoint {
#ReadOperation
#Bean
public String greet() {
return "Hello from custom endpoint";
}
}
The endpoint id i.e custom_endpoint needs to be configured in the list of actuator endpoints to be enabled.
application.properties :
management.endpoints.web.exposure.include=health,info,custom_endpoint
After a restart, endpoint works like a charm!

Spring WebFlux Handler Interceptor Adapter

I am migrating a Spring MVC library to Spring WebFlux. There is a feature that lets our clients annotate their controller methods to perform custom validation (and applying some business rules) on incoming headers before granting access to the API.
In Spring MVC we had that accomplished by using HandlerInterceptorAdapter. Since WebFlux doesn't have anything similar I was trying out the solution as suggested by Rossen here. However it doesn't work for this use case since the method handler info is only available in onSuccess operator and its too late to get the info for annotation processing.
I was trying out the other approach suggested there using #ModelAttribute method on a #ControllerAdvice but that only work if the annotation is applied to the Controller class in our case the annotation is applied on methods of controller class.
Here is a sample https://github.com/ranarula/handleInterceptor with the issue
Any pointers on how to go about implementing the annotation processing in WebFlux will help.

How to avoid putting #RefreshScope on multiple beans in my application

We are externalizing configuration of our microservices (spring boot based) using spring cloud.
As per my understanding on Spring Cloud, to enable the beans loading refreshed/updated values from Config server we need to do 2 things in Spring Cloud Client:
add #RefreshScope on the beans reading values from property files
using #Value
add spring actuator to provide /refresh endpoint to
refresh the context.
Scenario:
We have 100s of classes reading values from property file using #Value.
I have to mark all these beans refresh enabled using #RefreshScope annotation.
How can I avoid putting #RefreshScope annotation on all these classes.
Is there any shortcut or spring cloud feature to get around this situation.
You may want to look into Spring Boot feature called #ConfigurationProperties. It is designed to better organize several external configuration options.
According this Github issue, it should work for spring-cloud without #RefreshScope usage.
EDIT (reaction on comment): Maybe you are missing point of #ConfigurationProperties. With this annotation, you wouldn't use it in other configuration classes. You would have dedicated class (or few classes) only for reading and providing properties. Other configuration classes would inject this configuration holder bean.
You could encapsulate your #Values into one (or several) ConfigurationService bean which is #RefreshScoped and autowire this service into your classes instead. That way you only have a small amount of request scoped beans and your services can stay singletons.

Spring Boot Actuator Endpoint Override

I have been prototyping with Spring boot where I added dependency on spring-boot-starter-actuator and spring-boot-starter-data-rest and named my testing REST endpoint to /info. Application ran without any errors however my endpoint couldn't be called and app returned 404 all the time.
After some time I found out that actuator project contains SAME endpoint /info and basically overrides my custom RESTful endpoint since I didn't name it.
My question is: Is there any way how I can prevent such behavior in general (meaning bean clashing by mistake)? Or at least get WARN message when this is happening.
Thanks in advance for your answers
You can disable /info actuator endpoint by using the following property;
management.endpoint.info.enabled=false
Actually all can be disabled, or you can enable only certain ones, if you check the source link I've provided below;
By default, all endpoints except for shutdown are enabled. If you prefer to specifically “opt-in” endpoint enablement you can use the endpoints.enabled property.
source
For logging of this behaviour, while deploying you can see the endpoints and corresponding beans, you can deduce from this log I guess. But better not to use same endpoint with actuator while they are enabled.
Yes, there is a chance to disable particular classes by #EnableAutoconfiguration with a parameter exclude= where you can specify classname or whole package by using {} brackets
Example:
#EnableAutoConfiguration(exclude = {MyClassName.class}
#EnableAutoConfiguration(exclude = {MyClassName.class, MyClassName2.class})

Categories