Best practice for spring-boot REST response - java

I am new to spring and I am working on a fairly simple REST API.
I am getting a request without any data, and I need to send back some info. What would be the better way of doing so?
Entity
#RequestMapping(value = "/ping", consumes = "application/json", method = RequestMethod.GET)
public ResponseEntity<?> checkServerStatus() throws Exception {
Ping ping = new Ping();
ping.setStatus("alive");
ping.setVersion("v1");
try {
return ResponseEntity.ok().body(ping);
} catch (Exception e) {
throw new Exception("Service is not reachable at the moment", e);
}
}
OR
Response
#RequestMapping(value = "/ping2", consumes = "application/json", method = RequestMethod.GET)
public ResponseEntity<?> checkServerStatus2() throws Exception {
try {
return ResponseEntity.ok(new PingResponse("alive", "v1"));
} catch (Exception e) {
throw new Exception("Service is not reachable at the moment", e);
}
}
I figured no need to show PingResponse and Ping. They are typical get/set classes.
If both ways aren't ideal then maybe there is a better way of doing so?

The only difference is that you have your object in the try block or not. And that PingResponse could be an immutable object (no setters).
Entity/Response? they are both Objects.
So there is no difference worth taking notice in your provided code examples.

From your example it seems that, you just need to let the caller know that your service is up. Why are you creating an object? You can just notify the caller.
return new ResponseEntity<>("success", HttpStatus.OK);

you can just return the object from back end
#GetMapping("/ping")
public Ping checkServerStatus(){
Ping ping = new Ping();
ping.setStatus("alive");
ping.setVersion("v1");
return ping;
}

Related

External API call with next step or rollback

I have the following functionality to implement:
The method makes a call to an external API with POST (create operation) request. If the creation is valid, the next step is to create a bucket in S3. If the first step fails, whole method should thrown an exception.
What I came up with:
#PostMapping
public ResponseEntity<?> foo(String name) {
String requestEntity = //....
try {
ResponseEntity resp =
new RestTemplate().exchange("http://localhost:8080/rest/someservice",
HttpMethod.POST, requestEntity, String.class);
if (resp.getStatusCode().is2xxSuccessful()) {
myBucket.makeBucket(requestEntity);
return new ResponseEntity<>(/*Some success message*/);
} else return new ResponseEntity<>(/*Some error message*/);
} catch (RestClientException ex) {
return new ResponseEntity<>(/*Some error message*/);
}
}
Is it a valid solution or perhaps I should do it differently ie. with CompletableFuture?

How to control the HTTP response code from a Restlets resource?

I am currently working with the Restlets framework, and I cannot find a way to manually set the HTTP response code within a service method. Consider the following snippet of code:
public class MyResource extends ServerResource {
#Post("json")
public Representation doSomething(Representation entity) throws IOException {
int status = 200;
try {
// do something which might throw an exception
}
catch (Exception e) {
// log the exception
// *** I would like to assign HTTP status 500 here ***
status = 500;
}
JSONObject responseJSON = new JSONObject();
responseJSON.put("result", "some data");
Representation rep = new JsonRepresentation(responseJSON.toJSONString());
return rep;
}
}
I have the ability to catch and log an exception, should one occur, but it is not clear how I can change the HTTP response code. As far as I know, returning from doSomething will automatically be handled by Restlets with an 200 HTTP response code.
I know how to assign the status code directly from a filter or servlet, but is it possible to do this within Restlets, without going down the servlet layer?
As far as I know, there is an object called ResponseEntity which you can use to operate with microservices and a request-response programming model, which allows you to specify the returning HTTP return code. However, you need entities for this, and I think this goes below your abstraction level of Servlets.
You can change them to some predefined values such as HTTP.INTERNAL_SERVER_ERROR and such, which translate to a value in the end, which you can Google in the end.
I hope this was of some help
EDIT:
Import the necessary resource for a ResponseEntity object. In STS, it is
import org.springframework.http.ReponseEntity;
import org.springframework.http.HttpStatus;
public class MyResource extends ServerResource {
#Post("json")
public ResponseEntity<Representation> doSomething(Representation entity) throws IOException {
int status = 200;
try {
// do something which might throw an exception
}
catch (Exception e) {
ResponseEntity<Representation> response = null;
response = new ResponseEntity<Representation>(HttpStatus.INTERNAL_SERVER_ERROR);
return response;
}
JSONObject responseJSON = new JSONObject();
responseJSON.put("result", "some data");
Representation rep = new JsonRepresentation(responseJSON.toJSONString());
return rep;
}
And sorry for the delay. I am new to Stack Overflow

How should I handle a Java POST that can have a RequestBody of multiple types?

So I have a Spring RestController and one of my endpoints is used to perform operations on a generic typed object passed into my RequestBody as so:
#PostMapping("/endpoint")
public <T extends Comparable<T>> ResponseEntity<Integer> balancingPost(#RequestBody MyCustomObject<T> mco)
So after a lot of searching it doesn't seem this can be done without explicitly stating the type at some point. However as it stands my controller has no way of knowing the type (the program calling the POST does though). So how should I handle this? Is there a way to post my Class of T as well and somehow map it?
Try following
public ResponseEntity<?> balancingPost(#RequestBody MyCustomObject<T> mco) {
ResponseEntity<?> response = null;
try {
/*Some condition*/
if (!auth.equals(authCode)) {
response = new ResponseEntity<>("Unauthorized", HttpStatus.UNAUTHORIZED);
} else {
MyModel model = service.getModel();
response = new ResponseEntity<>(model, HttpStatus.OK);
}
} catch (Exception ex) {
response = new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
ex.printStackTrace();
}
return response;
}

RestEasy Interceptor

I wonder if it is as hard as I currently try to achieve it. I use Some Interceptor for security in my RESTEasy application. The interceptor implements javax.ws.rs.container.ContainerRequestFilter.
I use such a code to access request data:
if (((PostMatchContainerRequestContext) requestContext).getHttpRequest().getHttpMethod().equals("GET")) {
requestedId = Long.parseLong(requestContext.getUriInfo().getQueryParameters().get("id").get(0));
} else {
postDataMap = getPostData(requestContext);
}
and
private LinkedHashMap getPostData(ContainerRequestContext requestContext) {
Object obj = null;
try {
String result = IOUtils.toString(requestContext.getEntityStream());
ObjectMapper mapper = new ObjectMapper();
obj = mapper.readValue(result, Object.class);
System.out.println(obj);
} catch (IOException e) {
e.printStackTrace();
}
return (LinkedHashMap) obj;
}
But it seams ridiculous to access request data in such a way. Now I wanted to access DELETE-Request data but couldn't find any solution. Is there a much proper way to achieve what I am currently doing?
By intercepting you mean to check data before it goes to the rest layer? I have achieved this with implementing Filter interface (https://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/Filter.html).
Hope it helps.
Br,
Dusan
you can set security info in header,get value like this:
String logintoken = crc.getHeaderString("token");

How to send response before actions in spring mvc

Say that my spring controller function receives a large amount of data.
I want to return 200 OK, given that the data is structured right, and after that I want to perform the processing, which might take a while.
To my understanding the only way to send response is by return command. But I don't want to end the function on response send.
Are there other ways to send response to client at the middle of the function?
Creating a new thread run is obvious but other languages (JS) let you handle it more elegantly.
#RequestMapping(value = Connectors.CONNECTOR_HEARTBEAT, method = RequestMethod.POST)
public ResponseEntity<String> doSomething(#RequestBody List<Message> messages) {
HttpStatus code = (messages!=null && !messages.isEmpty()) ? HttpStatus.OK
: HttpStatus.NOT_FOUND;
return new ResponseEntity<String>(res, code);
// how do I add code here??
}
You can of course do processing after sending the response. The more general way would be to use the afterCompletion method of a HandlerInterceptor. By construction, it will be executed after the response have been sent to client, but it forces you to split you logic in 2 components the before part in controller, and the after part in the interceptor.
The alternative way is to forget Spring MVC machinery and manually commit the response in the controller:
#RequestMapping(value = Connectors.CONNECTOR_HEARTBEAT, method = RequestMethod.POST)
public void doSomething(#RequestBody List<Message> messages, HttpServletResponse response) {
int code = (messages!=null && !messages.isEmpty()) ? HttpServletResponse.SC_OK
: HttpServletResponse.SC_NOT_FOUND;
if (code != HttpServletResponse.SC_OK) {
response.sendError(code, res);
return;
}
java.io.PrintWriter wr = response.getWriter();
response.setStatus(code);
wr.print(res);
wr.flush();
wr.close();
// Now it it time to do the long processing
...
}
Note the void return code to notify Spring that the response have been committed in the controller.
As a side advantage, the processing still occurs in the same thread, so you have full access to session scoped attributes or any other thread local variables used by Spring MVC or Spring Security...
You can use #Async
#RequestMapping(value = Connectors.CONNECTOR_HEARTBEAT, method =
RequestMethod.POST)
public ResponseEntity<String> doSomething(#RequestBody List<Message>
messages) {
do();
HttpStatus code = (messages!=null && !messages.isEmpty()) ? HttpStatus.OK
: HttpStatus.NOT_FOUND;
return new ResponseEntity<String>(res, code);
}
#Async
void do(){
//your code
}
this work in java 8
I guess you mau use the async mechanism of spring
Async methods have been introduced in servlet 3.0 and Spring offers some support to them
Basically... you make a request; the request is handled by the server and then, in background, a new thread manages the requesta data
Here a useful link (at least i hope :) ) http://spring.io/blog/2012/05/10/spring-mvc-3-2-preview-making-a-controller-method-asynchronous/
You should use the HandlerInterceptor. But the code get a little bit more complex than expected. So, here's a code suggestion to make it simpler by putting the whole solution in a single class:
#RequestMapping(value = Connectors.CONNECTOR_HEARTBEAT, method = RequestMethod.POST)
public ResponseEntity<String> doSomething(#RequestBody List<Message> messages) {
HttpStatus code = (messages!=null && !messages.isEmpty()) ? HttpStatus.OK
: HttpStatus.NOT_FOUND;
result.set(res); // Save the object to be used after response
return new ResponseEntity<String>(res, code);
}
private static final ThreadLocal<String> result = new ThreadLocal<String>();
#Bean
public HandlerInterceptor interceptor() {
return new HandlerInterceptor() {
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// Get the saved object and clean for the next request
String res = result.get();
result.set(null);
// TODO Your code to be executed after response.
}
};
}

Categories

Resources