Jersey Viewable with status code - java

The JAX-RS implementation Jersey supports MVC style web applications through the Viewable class, which is a container for a template name and a model object. It is used like this:
#GET
public Viewable get() {
return new Viewable("/index", "FOO");
}
I wonder how a status code could be returned with this approach. The above would implicitly return 200, but that wouldn't be appropriate in any case. Is there a way to set a status code explicitly?

You will have to return a Response set up with the correct status code and headers containing your Viewable, e.g.:
#GET
public Response get() {
return Response.status(myCode).entity(new Viewable("/index", "FOO")).build();
}

Hmm you can create custom Response object in jersey thusly:
this will return a 200:
#GET
public Response get() {
URI uri=new URI("http://nohost/context");
Viewable viewable=new Viewable("/index", "FOO");
return Response.ok(viewable).build();
}
to return something different use this approach:
#GET
public Response get() {
int statusCode=204;
Viewable myViewable=new Viewable("/index","FOO");
return Response.status(statusCode).entity(myViewable).build();
}
Hope that helped....

Related

Spring ResponseEntity best practice

I am new to RESTful web services in general, and am learning the Spring implementation of web services.
I am particularly interested in learning how to properly use ResponseEntity return types for most of my use cases.
I have one endpoint:
/myapp/user/{id}
This endpoint supports a GET request, and will return a JSON formatted string of the User object whose ID is {id}. I plan to annotate the controller method as producing JSON.
In the case that a user with ID {id} exists, I set a status of 200, and set the JSON string of the user in the body.
In the event that no user exists with that ID, I was going to return some flavor of a 400 error, but I am not sure what to set in the body of the ResponseEntity. Since I annotate the endpoint method as producing JSON, should I come up with a generic POJO that represents an error, and return that as JSON?
You donĀ“t need to use a generic Pojo, using RequestMapping you can create different responses for every Http code. In this example I show how to control errors and give a response accordingly.
This is the RestController with the service specification
#RestController
public class User {
#RequestMapping(value="/myapp/user/{id}", method = RequestMethod.GET)
public ResponseEntity<String> getId(#PathVariable int id){
if(id>10)
throw new UserNotFoundException("User not found");
return ResponseEntity.ok("" + id);
}
#ExceptionHandler({UserNotFoundException.class})
public ResponseEntity<ErrorResponse> notFound(UserNotFoundException ex){
return new ResponseEntity<ErrorResponse>(
new ErrorResponse(ex.getMessage(), 404, "The user was not found") , HttpStatus.NOT_FOUND);
}
}
Within the getId method there is a little logic, if the customerId < 10 It should response the Customer Id as part of the body message but an Exception should be thrown when the customer is bigger than 10 in this case the service should response with an ErrorResponse.
public class ErrorResponse {
private String message;
private int code;
private String moreInfo;
public ErrorResponse(String message, int code, String moreInfo) {
super();
this.message = message;
this.code = code;
this.moreInfo = moreInfo;
}
public String getMessage() {
return message;
}
public int getCode() {
return code;
}
public String getMoreInfo() {
return moreInfo;
}
}
And finally I'm using an specific Exception for a "Not Found" error
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) {
super(message);
}
}
In the event that no user exists with that ID, I was going to return
some flavor of a 400 error, but I am not sure what to set in the body
of the ResponseEntity. Since I annotate the endpoint method as
producing JSON, should I come up with a generic POJO that represents
an error, and return that as JSON?
This is definitely a possible solution, if you want to add e.g. a more specific reason why the request failed or if you want to add a specific I18N message or just want to generify your API to provide some abstract structure.
I myself prefer the solution #Herr Derb suggested, if there is nothing to return, don't return anything. The returned data may be completely unnecessary/unused and the receiver may just discard it if the return code is anything else than 2XX.
This may be related:
http://www.bbenson.co/post/spring-validations-with-examples/
The author describes how to validate incoming models and builds a generic error response. Maybe this is something you want to do...

Spring Rest return a JSON response with a certain http response code

I am very new to Spring. I have a REST api written in Spring, but I don't know how to return a JSON response with a custom http response code.
I return a JSON response as follows:
public String getUser(String id){
...
return jsonObj;
}
But it always displays 200 http ok status code.
Here are my questions:
How can I synchronize the response JSON and HTTP code?
How is it possible to return JSON response and custom HTTP code in void function?
Use #ResponseStatus annotation:
#GetMapping
#ResponseStatus(HttpStatus.ACCEPTED)
public String getUser(String id) {...}
Alternative way: If you want to decide programmatically what status to return you can use ResponseEntity. Change return type of a method to ResponseEntity<String> and you'll be offered with a DSL like this:
ResponseEntity
.status(NOT_FOUND)
.contentType(TEXT_PLAIN)
.body("some body");
How I do it
Here is how I do JSON returns from a Spring Handler method.
My techniques are somewhat out-of-date,
but are still reasonable.
Configure Jackson
Add the following to the spring configuration xml file:
<bean name="jsonView"
class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
</bean>
With that,
Spring will convert return values to JSON and place them in the body of the response.
Create a utility method to build the ResponseEntity
Odds are good that you will have multiple handler methods.
Instead of boilerplate code,
create a method to do the standard work.
ResponseEntity is a Spring class.
protected ResponseEntity<ResponseJson> buildResponse(
final ResponseJson jsonResponseBody,
final HttpStatus httpStatus)
{
final ResponseEntity<ResponseJson> returnValue;
if ((jsonResponseBody != null) &&
(httpStatus != null))
{
returnValue = new ResponseEntity<>(
jsonResponseBody,
httpStatus);
}
return returnValue;
}
Annotate the handler method
#RequestMapping(value = "/webServiceUri", method = RequestMethod.POST)
you can also use the #PostMethod annotation
#PostMethod("/webServiceUri")
Return ResponseEntity from the handler method
Call the utility method to build the ResponseEntity
public ResponseEntity<ResponseJson> handlerMethod(
... params)
{
... stuff
return buildResponse(json, httpStatus);
}
Annotate the handler parameters
Jackson will convert from json to the parameter type when you use the #RequestBody annotation.
public ResponseEntity<ResponseJson> handlerMethod(
final WebRequest webRequest,
#RequestBody final InputJson inputJson)
{
... stuff
}
A different story
You can use the #JsonView annotation.
Check out the Spring Reference for details about this.
Browse to the ref page and search for #JsonView.

Spring MVC - How to return simple String as JSON in Rest Controller

My question is essentially a follow-up to this question.
#RestController
public class TestController
{
#RequestMapping("/getString")
public String getString()
{
return "Hello World";
}
}
In the above, Spring would add "Hello World" into the response body. How can I return a String as a JSON response? I understand that I could add quotes, but that feels more like a hack.
Please provide any examples to help explain this concept.
Note: I don't want this written straight to the HTTP Response body, I want to return the String in JSON format (I'm using my Controller
with RestyGWT which requires the response to be in valid JSON
format).
Either return text/plain (as in Return only string message from Spring MVC 3 Controller) OR wrap your String is some object
public class StringResponse {
private String response;
public StringResponse(String s) {
this.response = s;
}
// get/set omitted...
}
Set your response type to MediaType.APPLICATION_JSON_VALUE (= "application/json")
#RequestMapping(value = "/getString", method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
and you'll have a JSON that looks like
{ "response" : "your string value" }
JSON is essentially a String in PHP or JAVA context. That means string which is valid JSON can be returned in response. Following should work.
#RequestMapping(value="/user/addUser", method=RequestMethod.POST)
#ResponseBody
public String addUser(#ModelAttribute("user") User user) {
if (user != null) {
logger.info("Inside addIssuer, adding: " + user.toString());
} else {
logger.info("Inside addIssuer...");
}
users.put(user.getUsername(), user);
return "{\"success\":1}";
}
This is okay for simple string response. But for complex JSON response you should use wrapper class as described by Shaun.
In one project we addressed this using JSONObject (maven dependency info). We chose this because we preferred returning a simple String rather than a wrapper object. An internal helper class could easily be used instead if you don't want to add a new dependency.
Example Usage:
#RestController
public class TestController
{
#RequestMapping("/getString")
public String getString()
{
return JSONObject.quote("Hello World");
}
}
You can easily return JSON with String in property response as following
#RestController
public class TestController {
#RequestMapping(value = "/getString", produces = MediaType.APPLICATION_JSON_VALUE)
public Map getString() {
return Collections.singletonMap("response", "Hello World");
}
}
Simply unregister the default StringHttpMessageConverter instance:
#Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
/**
* Unregister the default {#link StringHttpMessageConverter} as we want Strings
* to be handled by the JSON converter.
*
* #param converters List of already configured converters
* #see WebMvcConfigurationSupport#addDefaultHttpMessageConverters(List)
*/
#Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.removeIf(c -> c instanceof StringHttpMessageConverter);
}
}
Tested with both controller action handler methods and controller exception handlers:
#RequestMapping("/foo")
public String produceFoo() {
return "foo";
}
#ExceptionHandler(FooApiException.class)
public String fooException(HttpServletRequest request, Throwable e) {
return e.getMessage();
}
Final notes:
extendMessageConverters is available since Spring 4.1.3, if are running on a previous version you can implement the same technique using configureMessageConverters, it just takes a little bit more work.
This was one approach of many other possible approaches, if your application only ever returns JSON and no other content types, you are better off skipping the default converters and adding a single jackson converter. Another approach is to add the default converters but in different order so that the jackson converter is prior to the string one. This should allow controller action methods to dictate how they want String to be converted depending on the media type of the response.
I know that this question is old but i would like to contribute too:
The main difference between others responses is the hashmap return.
#GetMapping("...")
#ResponseBody
public Map<String, Object> endPointExample(...) {
Map<String, Object> rtn = new LinkedHashMap<>();
rtn.put("pic", image);
rtn.put("potato", "King Potato");
return rtn;
}
This will return:
{"pic":"a17fefab83517fb...beb8ac5a2ae8f0449","potato":"King Potato"}
Make simple:
#GetMapping("/health")
public ResponseEntity<String> healthCheck() {
LOG.info("REST request health check");
return new ResponseEntity<>("{\"status\" : \"UP\"}", HttpStatus.OK);
}
Add produces = "application/json" in #RequestMapping annotation like:
#RequestMapping(value = "api/login", method = RequestMethod.GET, produces = "application/json")
Hint: As a return value, i recommend to use ResponseEntity<List<T>> type. Because the produced data in JSON body need to be an array or an object according to its specifications, rather than a single simple string. It may causes problems sometimes (e.g. Observables in Angular2).
Difference:
returned String as json: "example"
returned List<String> as json: ["example"]
Add #ResponseBody annotation, which will write return data in output stream.
This issue has driven me mad: Spring is such a potent tool and yet, such a simple thing as writing an output String as JSON seems impossible without ugly hacks.
My solution (in Kotlin) that I find the least intrusive and most transparent is to use a controller advice and check whether the request went to a particular set of endpoints (REST API typically since we most often want to return ALL answers from here as JSON and not make specializations in the frontend based on whether the returned data is a plain string ("Don't do JSON deserialization!") or something else ("Do JSON deserialization!")). The positive aspect of this is that the controller remains the same and without hacks.
The supports method makes sure that all requests that were handled by the StringHttpMessageConverter(e.g. the converter that handles the output of all controllers that return plain strings) are processed and in the beforeBodyWrite method, we control in which cases we want to interrupt and convert the output to JSON (and modify headers accordingly).
#ControllerAdvice
class StringToJsonAdvice(val ob: ObjectMapper) : ResponseBodyAdvice<Any?> {
override fun supports(returnType: MethodParameter, converterType: Class<out HttpMessageConverter<*>>): Boolean =
converterType === StringHttpMessageConverter::class.java
override fun beforeBodyWrite(
body: Any?,
returnType: MethodParameter,
selectedContentType: MediaType,
selectedConverterType: Class<out HttpMessageConverter<*>>,
request: ServerHttpRequest,
response: ServerHttpResponse
): Any? {
return if (request.uri.path.contains("api")) {
response.getHeaders().contentType = MediaType.APPLICATION_JSON
ob.writeValueAsString(body)
} else body
}
}
I hope in the future that we will get a simple annotation in which we can override which HttpMessageConverter should be used for the output.
Simple and Straightforward send any object or return simple List
#GetMapping("/response2")
#ResponseStatus(HttpStatus.CONFLICT)
#ResponseBody List<String> Response2() {
List<String> response = new ArrayList<>(Arrays.asList("Response2"));
return response;
}
I have added HttpStatus.CONFLICT as Random response to show how to pass RequestBody also the HttpStatus
Annotate your method with the #ResponseBody annotation to tell spring you are not trying to render a view and simple return the string plain

JAVA EE Rest conditional GET methods on QueryParams

I would like to have two GET methods on my Rest resource class.
one would react if query param has value1 and second on value2
Lets say:
#Path("/myApi")
public class MyApiService {
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response methodOne(...) {
...
return ...;
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response methodTwo(...) {
...
return ...;
}
How to achieve conditional routing for query params
I would like to methodOne() reacts if QueryParam is ?type=one and methodTwo() if QueryParam is ?type=two
Choosing servlet handlers based on QueryParam is not a good aproach, and by default no library gives you oportunity to do so.
The closest that comes to mind is PathParam, that is something like Path("\api\{param1}\{param2}") but it's not what you are looking for.
To achieve want your want just
unregister those methods as servlet handlers (Optional, if you don't need them outside of queryparam selection scope)
define a new one that will choose based on query param
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response methodThree(QueryParam('type') String type) {
return type.equals("type1") ? this.methodOne() : this.methodTwo();
}
You cannot have two methods with identical parameters for the same path.
It's not pretty, but it will work..
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response myMethod(#QueryParam("type") String type){
if(type.equals("one"))
return methodOne();
else
return methodTwo();
}

Manually serializing Jersey Response

I have a resource:
#Path("/")
public class Resource {
#GET
public Response getResponse() {
//..
final GenericEntity<List<BusinessObject>> entity = new GenericEntity<List<BusinessObject>>(businessobjects) { };
return Response.status(httpResultCode).entity(entity).build();
}
}
I want to unit test this method without using a Jersey client, but I don't know how to get the body of the Response object. I can't see a method that works. Here's the test method:
#Test
public void testMethod() {
Resource resourceUnderTest = new Resource();
Response response = resourceUnderTest.getResponse();
List<BusinessObject> result = ???;
}
I can get the result I want if I go though a Jersey Client, but I would rather just call the method directly without making any HTTP requests.
List<BusinessObject> result = (List<BusinessObject>)response.getEntity();
This will return the object you pass into the entity method of response builder. The Response object doesn't serialize the result. Looking at the previous method, getEntity will probably return GenericEntity> so you'd want code like this.
GenericEntity<List<BusinessObject>> result = (GenericEntity<List<BusinessObject>>)response.getEntity();

Categories

Resources