I am writing a REST based web service. I need to return all the responses as JSON format. I have an interceptor to validate my authentication parameters. On authentication failure scenario, I have to return the error response in JSON format.
Currently i am doing
response.setHeader("Content-Type","application/json");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "{\"error\":\"Missing Authentication Parameters\"}");
The response body is coming as below.
JBoss Web/2.1.3.GA - Error report HTTP Status 401 - {"error":"Missing Authentication Parameters"}type Status reportmessage {"error":"Missing Authentication Parameters"}description This request requires HTTP authentication ({"error":"Missing Authentication Parameters"}).JBoss Web/2.1.3.GA
I need just the JSON string in response. Please help me.
You should probably be using spring-security for this. If you want to do it by hand, an alternative to using sendError on the response is to use spring MVC's #ExceptionHandler along with content negotiation to return JSON.
First define an error class*:
public class Error {
public message;
public exception;
public Error(String message, Exception ex) {
this.message = message;
this.exception = ex;
}
}
And an exception:
public class NotAuthenticatedException extends Exception {
// ...
}
Then in your controller you throw an exception at the appropriate time, catch it with #ExceptionHandler and return a ResponseEntity containing an Error instance and the appropriate error code.
#Controller
public class SimpleController {
#RequestMapping(...)
public String aMethod() {
// ...
throw new NotAuthenticatedException("Missing Authentication Parameters");
}
#ExceptionHandler(NotAuthenticatedException.class)
public ResponseEntity<Error> handleNotAuthenticatedException(
NotAuthenticatedException ex,
HttpServletRequest request) {
return new ResponseEntity<Error>(
new Error(ex.getMessage(), ex),
HttpStatus.UNAUTHORIZED
);
}
}
*use getters/setters to please the java convention gods
Related
I have implemented REST API using spring-boot application. All my API's are now returning response in JSON format for each entity. This response was consumed by other server which expects all these response are in same JSON format. For example;
All my responses should be accommodated within the following structure;
public class ResponseDto {
private Object data;
private int statusCode;
private String error;
private String message;
}
Currently spring-boot returns error responses in a different format. How to achieve this using filter.
Error message format;
{
"timestamp" : 1426615606,
"exception" : "org.springframework.web.bind.MissingServletRequestParameterException",
"status" : 400,
"error" : "Bad Request",
"path" : "/welcome",
"message" : "Required String parameter 'name' is not present"
}
I need both error and successfull response are in same json structure all over my spring-boot application
This can be achieved simply by utilizing a ControllerAdvice and handling all possible exceptions, then returning a response of your own choosing.
#RestControllerAdvice
class GlobalControllerExceptionHandler {
#ResponseStatus(HttpStatus.OK)
#ExceptionHandler(Throwable.class)
public ResponseDto handleThrowable(Throwable throwable) {
// can get details from throwable parameter
// build and return your own response for all error cases.
}
// also you can add other handle methods and return
// `ResponseDto` with different values in a similar fashion
// for example you can have your own exceptions, and you'd like to have different status code for them
#ResponseStatus(HttpStatus.OK)
#ExceptionHandler(CustomNotFoundException.class)
public ResponseDto handleCustomNotFoundException(CustomNotFoundException exception) {
// can build a "ResponseDto" with 404 status code for custom "not found exception"
}
}
Some great read on controller advice exception handlers
I have a simple rest controller :
#RestController
#RequestMapping("/api/v1/")
public class OrderController {
#RequestMapping(value = "/orders2", method = RequestMethod.POST)
public OrderDto createOrder2(#RequestBody OrderDto order) throws Exception {
throw new Exception("Bouh!");
}
}
And I want to manage exceptions globally. From what I read it can be done with something like :
#ControllerAdvice
public class ErrorController {
#ExceptionHandler(Exception.class)
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
public ErrorDto handleConflict(HttpServletRequest request, Exception e) throws Exception {
ErrorDto o = new ErrorDto ();
o.setMessage(e.getMessage());
return o;
}
}
But when I make a post on my request, I get the following error :
26/10/2016 17:26:08.187 [http-nio-8080-exec-12] WARN o.s.web.servlet.PageNotFound -
No mapping found for HTTP request with URI [/duorest/api/v1/api/v1/orders2]
in DispatcherServlet with name 'rest'
I don't know why the uri change to /duorest/api/v1/api/v1/orders2
Some facts :
I checked in debug, my code is executed
If I move the method in the rest controller, I get no error and what I expect (my ErrorDto object)
Spring framework version 4.3.3.RELEASE
Spring-data-rest-webmvc version 2.5.4.RELEASE
Anybody already had this problem ? Or any hint ?
Is it resolved? if not please try to execute with #ResponseBody is missing on the handleConflict method.
I am really not sure if this is feasible using Spring 3.2 MVC.
My Controller has a method declared as below:
#RequestMapping(method = RequestMethod.GET)
#ResponseStatus(HttpStatus.OK)
public #ResponseBody List<Foo> getAll(){
return service.getAll();
}
Questions:
What is the meaning of #ResponseStatus(HttpStatus.OK) ?
Does it signifies that the method will always return a HttpStatus.OK status code.
What if an exception is thrown from the service layer?
Can I change the Response Status on occurrence of any exception?
How can I handle multiple response statuses depending on conditions in the same method?
#ResponseStatus(HttpStatus.OK) means that the request will return OK if the handling method returns normally (this annotation is redundant for this case, as the default response status is HttpStatus.OK). If the method throws an exception, the annotation does not apply; instead, the status will be determined by Spring using an exception handler.
How can I handle multiple response statuses depending on conditions in the same method?
That question has already been asked.
Can I change the Response Status on occurrence of any exception
You have two choices. If the exception class is one of your own, you could annotate the exception class with #ResponseStatus. The other choice is to provide the controller class with an exception handler, annotated with #ExceptionHandler, and have the exception handler set the response status.
If you return a ResponseEntity directly, you can set the HttpStatus in that:
// return with no body or headers
return new ResponseEntity<String>(HttpStatus.NOT_FOUND);
If you want to return an error other than 404, HttpStatus has lots of other values to choose from.
You cannot set multiple status value for #ResponseStatus. One approach I can think of is to use #ExceptionHandler for response status which is not HttpStatus.OK
#RequestMapping(value = "login.htm", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.OK)
public ModelAndView login(#ModelAttribute Login login) {
if(loginIsValidCondition) {
//process login
//.....
return new ModelAndView(...);
}
else{
throw new InvalidLoginException();
}
}
#ExceptionHandler(InvalidLoginException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
public ModelAndView invalidLogin() {
//handle invalid login
//.....
return new ModelAndView(...);
}
I have the following method skeleton in a Spring MVC application:
#RequestMapping(value = "/activateMember/{token}", method = RequestMethod.GET, produces = "text/html")
public String activateMember(#PathVariable("token") String token) {
...
}
I am trying to display an error message if the token is invalid for some reason. However I have no ModelAttribute in the method arguments and I don't really want one. But of course I can't use an Errors or BindingResults argument because of the absence of a ModelAttribute and its corresponding form.
So my question is:
what is the recommended way to display an error message given the above method signature and without introducing a ModelAttribute?
If the String you've returned from the method is a viewname (Spring default) then simply create a view for this case and do like:
#RequestMapping()
public String activateMember(#PathVariable("token") String token) {
if(checkToken(token)){
doProcess();
return "userprofile";
} else {
return "badtoken"
}
}
In more complicated case you may have a hierarchy of exceptions, related to bad tokens. (Token is expired, token is just incorrect and so on). You can register an #ExceptionHandler in the same controller:
#RequestMapping()
public String activateMember(#PathVariable("token") String token) {
return activate(token); // This method may throw TokenException and subclasses.
}
#ExceptionHandler(TokenException.class)
public ModelAndView tokenException(TokenException e){
// some code
return new ModelAndView("badtoken", "exception", e);
}
I'm migrating some servlets over to the Spring framework, using Spring MVC. Currently in each servlet we authenticate the user and if the authentication fails we do this:
if (authfailed)
{
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
"You are not authorized.");
return;
}
On the front end is a YUI-based application, and when an error status is returned the "failure" callback displays a dialog with the error message given above.
I know in my controller I can get the response object and call sendError, but is that the best way to handle this? sendError also throws an IOException so I'd have to catch that - a bit of annoying code to insert in every method of every controller.
I have the same problem handling exceptions - the servlets have try-catch blocks that call sendError in the catch method. I know I can mark my exception handlers with
#ExceptionHandler
#ResponseStatus(value = HttpStatus.NOT_FOUND)
but doesn't the exception handling class need to be in each controller class?
Finally, if the exception happens in a service called from a controller, does the exception bubble up to the controller or should I handle the exception in the service (thus pushing these exception handling issues into the service layer)?
This seems more difficult than it should be, but as with many things in Spring it's likely I don't understand what's going on. All I want to do is to send an error status and message back in the response!
Thanks,
Paul
It looks like you have the most of the answers in your question itself :)
To reiterate,
Have the controller like this
#RequestMapping("/test")
public String verifyAuth(HttpServletRequest request) throws NotFoundException {
String id = request.getParameter("id");
if (id == null)
throw new NotFoundException("Id not found in the request");
return "success";
}
Declare the exception class in NotFoundException.java,
#ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Id Not Found")
public class NotFoundException extends Exception {
public NotFoundException(String msg) {
super(msg);
}
}
This exception class need not be every controller class. Declare it as public class and import it in every required controller.
This is one way of doing it. If you like the non-spring style, declare HttpServletResponse in every controller arguments and do
#RequestMapping("/test")
public String verifyAuth(HttpServletRequest request, HttpServletResponse response) {
...
try {
response.sendError(..)
catch(..) {}
}
Or you can use views to show error message,
#RequestMapping("/test")
public String verifyAuth(HttpServletRequest request, Map<String, Object> map){
String id = request.getParameter("id");
if (id == null) {
map.put("status", HttpStatus.NOTFOUND);
map.put("reason", "Id Not Found");
return "error"
}
return "success";
}
Make sure your viewResolver is configured correctly and in the error.jsp to get the error string, you could say.
<body>
${status} ${reason}
</body>
Define error.jsp with nice css for all kind of errors you would expect.
These are not the only ways. With spring you have freedom to do anything. I have seen few ppl rendering json object for error message.
To answer your another question of if the error happens in the service called by the controller is depend on your scenario. For example you are trying to read the user store, if the user store not available error happens, I would handle there itself to read from another replica user store if one available and If I found user does not exist I would leave the exception to the controller to throw.