PDA

View Full Version : returning JSON with 401 header



shaine
Mar 13th, 2012, 09:08 AM
Hi

I have been searching and cannot find how to do this.

I can make my controller return 401 status, using @ResponseStatus, but am unable to return the underlying json. is it even possible to do this? or am I approaching it incorrectly?


@Controller
public class AuthenticationController {

@RequestMapping(method=RequestMethod.GET, value="/AuthenticateUser", produces="application/json")
public @ResponseBody Object authenticateUser(@RequestParam("userId") String userId, @RequestParam("password") String password, @RequestParam("appId") String appId ,@RequestParam("appVersion") String appVersion, @RequestParam("uuid") String uuid) throws Error {
if (userId.equals("dog")) {
return new AuthToken();
} else {
throw new Error();
}
}
}

class AuthToken {
public String authToken = "1234";
}

@ResponseStatus(value=HttpStatus.UNAUTHORIZED)
class Error extends Exception {
public String errorMessage = "an error";
}

michal.jemala
Mar 13th, 2012, 11:22 AM
Hi Shaine,

in the simplest scenario you can achieve this by creating exception handling method and annotate it as follows:


@Controller
public class AuthenticationController {

@RequestMapping(method=RequestMethod.GET, value="/AuthenticateUser", produces="application/json")
public @ResponseBody Object authenticateUser(
@RequestParam("userId") String userId,
@RequestParam("password") String password,
@RequestParam("appId") String appId,
@RequestParam("appVersion") String appVersion,
@RequestParam("uuid") String uuid) throws Error {
if (userId.equals("dog")) {
return new AuthToken();
} else {
throw new Error();
}
}


@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler({Error.class})
@ResponseBody
public String handleNotFound(Error e) {
return e.errorMessage;
}

}

class AuthToken {
public String authToken = "1234";
}

class Error extends Exception {
public String errorMessage = "an error";
}


The drawback of this solution is that you can only return String values as there is a limited set of supported return types (see JavaDoc for org.springframework.web.bind.annotation.ExceptionH andler annotation.)

NOTE: If you need more more flixible exception handling consider creating a custom implementation of org.springframework.web.servlet.HandlerExceptionRe solver interface.

Hope this helps.

Michal

michal.jemala
Mar 13th, 2012, 11:51 AM
Hi Shaine,

the previous solution is a a bit of hack, there is actually a much more clean and elegant solution for your problem. Use org.springframework.http.HttpEntity<T> as a return type as follows



@Controller public class AuthenticationController {
@RequestMapping(method=RequestMethod.GET, value="/AuthenticateUser", produces="application/json")
public @ResponseBody Object authenticateUser(
@RequestParam("userId") String userId,
@RequestParam("password") String password,
@RequestParam("appId") String appId,
@RequestParam("appVersion") String appVersion,
@RequestParam("uuid") String uuid) throws Error {
if (userId.equals("dog")) {
return new AuthToken();
} else {
SomeErrorType errorType = // instantiate and initialize some error type
return new HttpEntity<SomeErrorType>(errorType, HttpStatus.UNAUTHORIZED);
}
}
}
class AuthToken {
public String authToken = "1234";
}
class SomeErrorType {
// some properties of error type
}


The major advantage for this solution is that you can use an arbitrary type for HttpEntity body and do not need to create custom exception handlers.

Cheers,
Michal

shaine
Mar 13th, 2012, 12:28 PM
Hi Michal

Thanks a lot for the response.

Ideally I would like to not implement this, but I am required to implement an API which expects the 401 + JSON, so I have no choice.

Your solution is exactly what I was looking for, thank you very much