Can I do a GET with request body in Spring Boot? - java

I'm using Spring Boot and Spring MVC and I need to make a GET with a request body. Is this possible?
I tried this but it's not working. I get 404.
#RestController
#RequestMapping("/api")
public class HomeController {
#GetMapping("/v1/foo")
public ApiRes postBody(#RequestBody ApiReq apiReq) {
...
}
}

Technically it is possible but it is against the HTTP API Design Guidelines.
Request-Bodys should only be used for POST or PUT.
For further information: https://swagger.io/resources/articles/best-practices-in-api-design/

Related

Spring Cloud Gateway as a gateway as well as web application

I have a spring cloud gateway application and what I want is like if there are two routes then on one route it should redirect to some external application but for other route it should forward the request to same app with a particular url.
-id: my_local_route
predicates:
- Path="/services/local"
uri: "/mylocal/services/local" //can we do something like that
Please note I want to create my rest services in same app as in spring cloud gateway. I understand it is not correct approach but for my knowledge I wanted to know whether it is possible or not.
If you have some rest APIs within your spring-cloud-gateway project, you don't need to explicitly put the routes for it.
So suppose you have following rest api in gateway project
#RestController
#RequestMapping("test")
class Controller{
#GetMapping("hello")
public String hello(){
return "hello";
}
}
and for external-url, you want to send some traffic to let's say https://httpbin.org. So in gateway application.yml could look something like this:
spring:
cloud:
gateway:
routes:
- id: httpbin-route
uri: https://httpbin.org
predicates:
- Path=/status/**
With this request like
http://localhost:8080/test/hello will be resolved by your rest controller
http://localhost:8080/status/200 will be redirected to httpbin site
If for some reason you have the same root path for both cases, the controller will have precedence.
If you have the same endpoint in gateway predicates and controller, by default controller will take precedence over predicates, if you want predicates to take precedence over controller, just create a BeanPostProcessor to adjust the order:
#Component
public class RequestMappingHandlerMappingBeanPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof RequestMappingHandlerMapping) {
((RequestMappingHandlerMapping) bean).setOrder(2); // After RoutePredicateHandlerMapping
}
return bean;
}
}

No cache header in Spring Boot response from RestController

I have a typical controller which returns JSON and I need to return no-cache header as a part of a response. Please note at this moment I have no spring security on classpath, however if there is need to make it to work out-of-the-box then I'm fine with this.
Currently I have implemented this in the following manner:
public static <T> ResponseEntity<T> createResponseSpringWay(final T body) {
org.springframework.http.CacheControl cacheControl = org.springframework.http.CacheControl.noCache();
return ResponseEntity.ok().cacheControl(cacheControl).body(body);
}
Is there any spring boot property that can make it automatically for me? I want to get rid of ResponseEntity at all methods.
I've tried the following configuration, but I believe it only applies to static resources, so it doesn't work:
spring.resources.cache.cachecontrol.no-store=true
spring.resources.cache.cachecontrol.must-revalidate=true
spring.resources.cache.cachecontrol.no-cache=true

Exclude path params from actuator metrics

I have a Spring boot application that uses the actuator metrics and I have the following issue:
I have an endpoint like this :
GET /users/{userId}
So every time I call this endpoint I use a different Id to get the specific user as you can think we can have hundreds of thousands. It is working correct, but i noticed that when calling my metrics endpoint :
GET /metrics
I get something like this:
counter.status.200.metrics: 1,
counter.status.200.api.users.4: 2,
counter.status.200.api.users.2: 3,
counter.status.200.api.users.3: 2,
So it makes me think that i will get a counter for every single call with different path params, so my question is how can i have a counter just for the endpoint /users/{anyId} and not for every single combination excluding the parameters?.
--- EDIT ---
I'm using Spring boot + Jersey (I'm not using Spring MVC), the following is my controller code:
#Component
#Path("/users")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class UserResource {
#GET
public Response getUsers() {
return Response.ok("It works !").build();
}
#GET
#Path("/{userId}")
public Response getUserById(#PathParam("userId") String id) {
return Response.ok("It works !").build();
}
}
And the following is the Jersey configuration:
#Component
#ApplicationPath("/api")
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(UserResource.class);
register(PingResource.class);
}
}
It's a known issue with Spring Boot 1.x when using Jersey. There's a workaround described in the issue, alternatively you can disable the metrics filter by adding the following to application.properties:
endpoints.metrics.filter.enabled=false

Configure Spring interceptor for controllers only

I'm trying to configure a Spring interceptor for controllers only in the following way. For the beginning I want to exclude all the requests starting with /swagger. I try to do it in the following way:
registry.addInterceptor(myInterceptor).addPathPatterns("/**").excludePathPatterns("/swagger**");
However, interceptor gets fired. Where is a mistake?
Maybe, there is an alternative solution with #ControllerAdvice. But I need to get request headers, so I guess it doesn't fit my needs.
Thanks for any help!
Try to use "/swagger*/**" or "/swagger*" instead of "/swagger**"
I solved the problem in the following way:
#ControllerAdvice
public class SomeAdvice {
#ModelAttribute
public void token(HttpServletRequest request) {
// getting headers and setting the attribute in the request
request.setAttribute("theAttribute", new SomeObject());
}
}
And then I get the request attribute in a controller this way:
public void someMethod(#RequestAttribute("theAttribute") SomeObject someObject) {
// some logic goes here
}
P.S. And one more note. If you're using Swagger you'll get into the trouble as Swagger will consider this attribute as controller method parameter. To ignore it you can use the following snapshot of configuration:
.ignoredParameterTypes(SomeObject.class);

spring boot actuator endpoint mapping root class

In spring we can design rest web service like below.
#RestController
public class HelloController {
#RequestMapping(value = "/hello", method = RequestMethod.GET)
public String printWelcome(ModelMap model) {
model.addAttribute("message", "Hello");
return "hello";
}
}
When we do so, #RestController & #RequestMapping will internally manage request mapping part. So when I will hit url i.e. http://localhost:8080/hello it will point to printWelcome method.
I was looking into spring boot actuator source code. If we will use spring boot actuator in our application it will provide us some endpoints, which has exposed as rest APIs like health, metrics, info. So in my application if I am using spring boot actuator, when I will hit the url like "localhost:8080/health" I will get response.
So now my question is in spring boot actuator source code where this URLs get mapped. I have debugged source code of spring boot actuator, but not able to find out the root class of mapping of endpoints.
Can anyone please help ?
here it is , In AbstractEndpoint it says
/**
* Endpoint identifier. With HTTP monitoring the identifier of the endpoint is mapped
* to a URL (e.g. 'foo' is mapped to '/foo').
*/
If you see HealthEndPoint it extends AbstractEndpoint and does a super("health", false); , thats where it maps to "localhost:8080/health".
All spring-boot-actuator endpoints extends AbstractEndpoint (In Health endpoint case for example: class HealthEndpoint extends AbstractEndpoint<Health>) which construcor has the id of the Endpoint.
/**
* Endpoint identifier. With HTTP monitoring the identifier of the endpoint is mapped
* to a URL (e.g. 'foo' is mapped to '/foo').
*/
private String id;
Otherwise, it has an invoke method (from interface Endpoint) through it is invoked the endpoint.
/**
* Called to invoke the endpoint.
* #return the results of the invocation
*/
T invoke();
Finally, this endpoints are configured in the class EndpointAutoConfiguration as Bean:
#Bean
#ConditionalOnMissingBean
public HealthEndpoint healthEndpoint() {
return new HealthEndpoint(this.healthAggregator, this.healthIndicators);
}
Take a look this post where explains how to custom your endpoint:
http://blog.codeleak.pl/2014/10/spring-boot-actuator-custom-endpoint.html

Categories

Resources