Reputation: 3101
I was wondering how to correctly implement a Spring Controller which is supposed to serve as a REST Service. Especially I want to try and make the interface as RESTful as possible. Also i'd like to make use of HTTP Error codes so my Clients can act accordingly.
I was wondering how to implement my Methods, so they return JSON if everything works fine(in the body of the response) or toss a http error code as well as a custom reason why it didnt work(maybe errors that came from the DAO or the database). However I'm not sure which one is the right way? return a String and add the values to return to a Model, or return a HashMap and put my stuff in there? or return the objects directly? but then what if an error occures and i cannot return said Class? return null instead? I post 2-3 ways of doing it that i could imagine:
@RequestMapping(value="/addUser", method= RequestMethod.POST)
public String addUser(@RequestBody User user, HttpServletResponse response, Model model) throws Exception{
try{
userService.addUser(user);
model.addAttribute("user", userService.getUser(user.getUsername(), user.getPassword()));
return "user";
}catch(Exception e){
model.addAttribute("error", e.toString());
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString());
return "error";
}
}
Or rather this way:
@RequestMapping(value="/addUser", method= RequestMethod.POST)
public @ResponseBody Map addUser(@RequestBody User user, HttpServletResponse response){
Map map = new HashMap();
try{
userService.addUser(user);
map.put("success", true);
map.put("username", user.getUsername());
}catch (KeyAlreadyExistsException e){
map.put("success", false);
map.put("Error", e.toString());
response.sendError(HttpServletResponse.SC_FORBIDDEN, e.toString());
}catch(Exception e){
map.put("success", false);
map.put("Error", e.toString());
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString());
}
finally {
return map;
}
}
I realize code is not "just right" but i cannot figure out how to make it the way it needs to be. Maybe some experiences responses would help? Thx for the support already
Upvotes: 25
Views: 33383
Reputation: 17
If you want your whole Exception with stackTrace to be transmitted toward your client, as @Bart said you should send an "ErrorResource" object.
A library has it off-the-shelf :
<dependency>
<groupId>com.github.zg2pro</groupId>
<artifactId>spring-rest-basis</artifactId>
<version>0.2</version>
</dependency>
add it to your project and then just add a "@ControllerAdvice" class to your beans, as it is explained in the project wiki.
That should handle your errors nicely!
Upvotes: 0
Reputation: 17361
Firstly, I think you should always return a object when returning JSON. Even when something goes horribly wrong.
When something goes wrong you simply set response.setStatus()
and return a resource describing the error.
public class ErrorResource implements Resource {
private final int status;
private final String message;
public ErrorResource(int s, String m) {
status = s;
message = m;
}
public int getStatus() {
return status;
}
public String getMessage() {
return message;
}
}
The resource gets serialized and the outcome would be
{"status":500, "message":"Yay!"}
Using a Map
will work but I would like to advise you to write some resource classes which define the object to be returned. They would be easier to maintain. Maps
don't offer any structure while structure is a very important part when creating a REST service.
I don't think you should return a resource with the raw exception message embedded. It can potentially leak information you don't want anyone to see.
Upvotes: 16
Reputation: 1
use ResponseEntity class to exploit error with http status code.
You could try the following code:
@RequestMapping(value = "/profile", method = RequestMethod.GET)
@ResponseBody @ResponseStatus(value = HttpStatus.OK)
public ResponseEntity<UserVO> getUserProfile()
{
string userName = getUserAuthentication().getName();
if (StringUtils.isEmpty(userName)) RestUtil.defaultJsonResponse("");
User user = userService.getUserByUserNameWithCounters(userName);
return RestUtil.getJsonResponse(new UserVO(user));
}
Upvotes: 0
Reputation: 12942
you can use @ExceptionHandler
with @ControllerAdvice
check this link
Upvotes: 8
Reputation: 4239
You could also catch your exceptions with @ExceptionHandler
annotated methos within your Rest Controller.
@ExceptionHandler(Exception.class)
@ResponseBody
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public String handleException(Exception e) {
return "return error object instead";
}
this will make your acutal controller/business logic cleaner.
Upvotes: 31