I can define a GET method in two ways:
public ResponseEntity<Pet> getPetById(Long id);
and
public Pet getPetById(Long id);
They seem to be equivalent, except that the first one involves more boilerplate code.
So, what is the reason to use ResponseEntity and what advantages it brings?
The difference is quite easy to explain. When you use ResponseEntity, you have full control about the contents of your response. You can change your headers, status code, ...
When you don't use ResponseEntity as the return type of a controller method, spring will "automagically" create a default ResponseEntity.
So the biggest advantage in using ResponseEntity is that you have full control. The disadvantage is that it is more verbose than letting Spring work its magic.
Related
Code convention says no logic in the controllers. All should be handled in the service layer. My question is especially about returning ResponseEntity.
Should it be handled in RestController or in Service layer?
I tried both ways. I think RestController is the suitable place to return ResponseEntity. Because we are using mappings in the RestController.
On the other hand, we know the controllers should not include any logic.
#GetMapping("/{id}")
public ResponseEntity<Employee> getEmployee(#PathVariable Long id) {
return ResponseEntity.ok(employeeService.findEmployeeById(id);
}
or
#GetMapping("/{id}")
public ResponseEntity<Employee> getEmployee(#PathVariable Long id) {
return employeeService.findEmployeeById(id);
}
ControllerAdvice for exception handling is my another concern. Which way is the best to use?
Thanks for your advance.
Code convention says no logic in the controllers.
Not really. Code convention says each layer has to perform itself logic which it is responsible of.
Computing the result, retrieving data requested/needed by the request is clearly not the rest controller job but sending an http response, what returning ResponseEntity does is its job. So this looks the correct way :
#GetMapping("/{id}")
public ResponseEntity<Employee> getEmployee(#PathVariable Long id) {
return ResponseEntity.ok(employeeService.findEmployeeById(id);
}
If the ResponseEntity was produced by your service, your service would be coupled with the Http layer. Not desirable and make it less reusable as a service.
Status Code, Response Body, Headers are one of the core parts for REST
The controller should be concerned with accepting the request, asking the correct domain service to process the request, and handing off the response to the correct place.
It's right that controllers should not perform all business logic here but sending the HTTP response should be done in Controller instead of service.
Although Status code can be sent using #ResponseStatus(HttpStatus.XXX) which might not be helpful for in scenarios where we have to send Status Code according to the conditions. You can create custom ResponseDTO which generally have body, message and status code.
public ResponseEntity<ResponseDTO> method() {
return new ResponseEntity<ResponseDTO>(response,response.getStatus());
}
First. The business logic should be handled in the service layer where you are able to abstract the data access with repository. This aides modular programming, reusable pieces of codes decoupled from each other. This is the idea behind Model, View, Controller(MVC), the underlying design. In terms of testing, it will be easier to have these parts of the application do their part of the job and testing independent of one another. Abstracting your logic in the service method also helps when we are dealing with security access to specific methods not URL which the controller gives us the ability. Therefore, your RestController should call your service layer and return appropriate response.
Second. For your (Rest) ControllerAdvice, having your exception handler aids in returning custom errors. Here is an example below inside the exception handler class.
#ExceptionHandler(CustomerExistException.class)
public final ResponseEntity<ApiErrorResponse> handleCustomerExistException(
CustomerExistException ex) {
ApiErrorResponse errorResponse = new ApiErrorResponse("USR_04", "The email already exists."
+ "Email", String.valueOf(HttpStatus.BAD_REQUEST));
return new ResponseEntity<ApiErrorResponse>(errorResponse, HttpStatus.BAD_REQUEST);
}`
I have a controller that exposes the following endpoint:
#RequestMapping("/all-users")
List<User> getAllUsers() {
...
}
I have also an annotation that helps me out with versioning of those endpoints, which ends up on something like this:
#RequestMapping("/all-users")
#Version(version=1, latests=LATEST_ALL_USERS)
List<User> getAllUsers() {
...
}
Now I want to introduce an additional standard behavior to all handlers mapped wish method contains #Version annotation which will simply wrap the response object into another object which contains the current version and latest version of the invoked method. Some information to build this object are provided by #PathVariable parameters. I'm trying to find a hook that allows me that but no luck so far.
I tried first to have a custom RequestResponseBodyMethodProcessor but if I add it will not take any effect because the original RequestResponseBodyMethodProcessor comes before and I don't want to remove the ResponseBody from my endpoints.
Afterward I tried to go for the mapping instead, once I cannot handle it on the processor, maybe I could handle that on mapping time introducing my code pre and post method invocation, but got stuck on the point where mapping is registered where a method object is needed, not allowing me to introduce my advice code.
Is there any way to get this done?
Edit:
Some of the information needed to build the new returned object are provided as #PathVariables, and are available on end-point method call.
I am wondering if there is a way to wrap all argument resolvers like for #PathVariables or #ModelAttributes into one single transaction? We are already using the OEMIV filter but spring/hibernate is spawning too many transactions (one per select if they are not wrapped within a service class which is be the case in pathvariable resolvers for example).
While the system is still pretty fast I think this is not necessary and neither consistent with the rest of the architecture.
Let me explain:
Let's assume that I have a request mapping including two entities and the conversion is based on a StringToEntityConverter
The actual URL would be like this if we support GET: http://localhost/app/link/User_231/Item_324
#RequestMapping("/link/{user}/{item}", method="POST")
public String linkUserAndItem(#PathVariable("user") User user, #PathVariable("item") Item item) {
userService.addItem(user, item);
return "linked";
}
#Converter
// simplified
public Object convert(String classAndId) {
return entityManager.find(getClass(classAndId), getId(classAndId));
}
The UserService.addItem() method is transactional so there is no issue here.
BUT:
The entity converter is resolving the User and the Item against the database before the call to the Controller, thus creating two selects, each running in it's own transaction. Then we have #ModelAttribute methods which might also issue some selects again and each will spawn a transaction.
And this is what I would like to change. I would like to create ONE readonly Transaction
I was not able to find any way to intercept/listen/etc... by the means of Spring.
First I wanted to override the RequestMappingHandlerAdapter but the resolver calls are well "hidden" inside the invokeHandleMethod method...
The ModelFactory is not a spring bean, so i cannot write an interceptor either.
So currently I only see a way by completely replacing the RequestMappingHandlerAdapter, but I would really like to avoid that.
And ideas?
This seems like a design failure to me. OEMIV is usually a sign that you're doing it wrong™.
Instead, do:
#RequestMapping("/link/User_{userId}/Item_{itemId}", method="POST")
public String linkUserAndItem(#PathVariable("userId") Long userId,
#PathVariable("itemId") Long itemId) {
userService.addItem(userId, itemId);
return "linked";
}
Where your service layer takes care of fetching and manipulating the entities. This logic doesn't belong in the controller.
I have been trying to get exception handling working in my simple Spring 3 based ReST web services. Based on everything I have seen, there is a bug that prevents this from working automatically with the #ResponseBody and #ExceptionHandler annotations
https://jira.springsource.org/browse/SPR-6902
So given that it isn't supported until Spring 3.1 or 3.0.6, what is the current best method for doing exception handling? I have seen numerous posts but haven't found a clear answer that has worked for me. An ideal solution would be one that automatically provides support for both xml and json
Do I have to manually define the entire marshalling setup? Won't this remove the need for the annotations that make using Spring 3 rest support worth it?
Seems in order to manually define marshalling (i.e. Jaxb2Marshaller) I need to add a new dependency on spring-ws which is a bit of a pain
Is it easier to just define a 'Response' object that all my methods return and wrap all functions in try/catch blocks?
You can redirect on error and then return something in #ResponseBody:
#ExceptionHandler(Exception.class)
public ModelAndView handleMyException(Exception exception) {
return new ModelAndView("redirect:errorMessage?error="+exception.getMessage());
}
#RequestMapping(value="/errorMessage", method=RequestMethod.GET)
#Responsebody
public String handleMyExceptionOnRedirect(#RequestParameter("error") String error) {
return error;
}
Little ugly, but this is just work around till the fix will be available.
This is a good workaround, but with one addition. The #ExceptionHandler(Exception.class)
should be #ExceptionHandler(MyException.class, YourException.class) as you can get into a loop using the general Exception class.
You can then test for (ex instanceof Myexception) to determine the message to display if need be.
I have some POJOs which are the basis for this RESTful API I am working on. However, some of the responses I need to include some other information to make the API more complete. I really don't want to put these extra information in the POJO, but include it at the web service layer as if it were.
It deals with "People" who have "Appointments". Each appointment only has one person.
So, I have a RESTful call like /Patients/1 and it basically grabs the POJO for the Person and I am currently using XStream to serialize it and send it on its way. This works great, but I would like to do something like this:
<Person>
<firstName>James</firstName>
... other fields ...
<nextAppointment href="/Appointment/12345>2010-02-19</nextAppointment>
<prevAppointment href="/Appointment/12346>2010-01-01</prevAppointemnt>
</Person>
Where next and prev appointment are not actually included in the Person POJO. I am looking for a good "spring way" to accomplish this. The client could do something like this /Patients/1/PreviousAppointment and /Patients/1/NextAppointment, but I am looking to cut the amount of calls (maybe pre-optimization?) and give them a way to get more information if they need it by using he href.
It is very elegant using the XStreamMarshaller since all I do it hand the view the POJO or list of POJO and it handles it. But I need to doctors those up a bit before they are sent out.
Thanks!
This is the problem with handing your business objects directly to the marshaller - you have very little flexibility in how they turn that object into the response. There is something to be said for pre-transforming the objects yourself, you get more control that way.
So if you have a specific output structure that you want, then with XStream you need to build a class structure that looks like it. You then transform your business objects into that class structure, and pass that to XStream instead.
It may seem less elegant, but your system will be much less prone to being broken by small changes in your business object model, which you your current XStream-based system will be.
Solution to your problem : CREATE A CUSTOMIZEDCONVERTER...
public class CustomizedConverter implements Converter {
#Override
public void marshal(Object source, HierarchicalStreamWriter writer,MarshallingContext context) { ....}
#Override
public Object unmarshal(HierarchicalStreamReader reader,UnmarshallingContext context) {..}
#Override
public boolean canConvert(Class clazz) {..}
}
To know what to use the converter with the Marshaller refer this.
So basically the CONVERTER works on the POJO and ensures we get the XML response as given in the contract.