Different response from a controller method based on HTTP Response code - spring

How do you write a controller method which can either return a View or HTTP response status code based on if its 200 then view else the response status code.
#RequestMapping(value="/",method=RequestMethod.GET)
public String showLanding()
{
return View.Landing;
}
I want to handle in case of 401, 403, 500 etc. just status code should be returned instead of view.

To return the 403- Unauthorized status code,
#RequestMapping(value="/",method=RequestMethod.GET)
public String showLanding()
{
return HttpStatus.UNAUTHORIZED;
}
See this:
http://docs.spring.io/spring/docs/3.1.x/javadoc-api/org/springframework/http/HttpStatus.html?is-external=true
How to respond with HTTP 400 error in a Spring MVC #ResponseBody method returning String?

You could also check out the #ResponseStatus annotation as well as ResponseEntity (for more dynamic scenarios)

I'm far from suggesting that you should do flow control with Exceptions - but those HTTP statuses are errors and exceptions. So you might want to throw business exceptions from your controller methods and then handle those using #ExceptionHandlers.
You can also target a subset of Controllers and assist those with Exception handling using #ControllerAdvice.

Related

How to handle Optional from Service to Controller in Spring?

Spring JPA returns an Optional. I return the Optional from the Service. There if Optional is not present I pass error to model. The other case if there is a database error for example database not available, I do not catch these exceptions. If that happens user will see this exception in browser. I do not know how to handle this very rare error. For me this should never happen and if it does, ok . I do not want to handle this exception all the time. What do you think about my architecture.
Service:
#Override
public Optional<Client> findClientById(Long id) {
return clientRepository.findById(id);
}
Controller:
Optional<Client> client= clientService.findClientById(id);
if(client.isPresent())
{
model.addAttribute("client", client.get());
}
else
{
model.addAttribute("error", "No clientfound with this ID!!");
}
Firstly, you shouldn't pass error as an attribute in your model - that's REST anti-pattern. The best way to hand this is to use HTTP codes, e.g. return 502. To do so, you may wrap your exceptions up your code into HttpResponse. To catch your exception, you may approach similar to method that explained here, i.e. catch spring data exception, wrap it up a way you wanted and throw on higher level for processing.

Spring MVC test post method with controller redirect

I have a test:
#Test
public void shouldAddCompany() throws Exception {
mockMvc.perform(post("/companies")
.param("name", "companyName"))
.andExpect(model().attribute("company",
hasProperty("name", is("companyName"))));
}
and my controller method looks like that:
#PostMapping("/companies")
public String displayCompaniesPost(#ModelAttribute Company company) {
companyService.save(company);
return "redirect:/companies";
}
How can i check company attribute in test? There is a problem because of redirect and status 302.
java.lang.AssertionError: Model attribute 'company'
Expected: hasProperty("name", is "companyName")
but: was null
I think it occurs because controller is going to GET method because of redirection. When I remove this redirection everything is ok, but I don't want to remove that redirection.
EDIT (GetMapping):
#GetMapping({"/", "/companies"})
public String displayCompanies(Model model) {
model.addAttribute("company", new Company());
List<Company> companies = companyService.findAll();
model.addAttribute("companies", companies);
return "companies";
}
I thought the problem is because of addding attribute with the same name in getMapping, but when I removed it, it still doesn't work.
You need to modify your approach. If you POST to a controller method, and it returns a Redirect you will have no ability to access any model information set by that controller, it just returns an HTTP 302 with a Location Header to the client telling it the new url to go to (in this case GET /companies). If this is a strictly Unit test, that is the extent of what you can test for this method.
I would consider instead treating this as an integration test, and change your test to have two separate steps:
POST /companies and validate that the response is the expected redirect
GET /companies and validate that the list of companies returned contains the new company you posted in step 1

Returning HTTP 403 substatus from Asp.Net WebApi controller

I'd like to return Http 403 errors from my Asp.Net WebApi controllers when the user does not have permission to perform certain tasks.
However, I'd like to use a substatus on this to give further details about the error, along with the error message.
At the moment, what I get is
HTTP/1.1 403 Read access forbidden
but what I'd like to see is
HTTP/1.1 403.2 Read access forbidden
The code I'm using currently:
[HttpGet]
public EnrollmentDetail Details(int id)
{
var enrollmentDetail = _context.GetEnrollmentDetail(id);
if (!enrollmentDetail.R)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Forbidden)
{
ReasonPhrase = "Read access forbidden"
});
}
return enrollmentDetail;
}
I can't find any information any where on how to add these sub-statuses to the response. Is there any way it can be done with the built-in classes? If not, is there a way to write a custom HttpException which could do this for me?
That's because sub-statuses are not part of the HTTP spec and should not be used. If you want to send more details about the problem you encountered, take a look at Json-problem

Spring mvc controller null return handler

#RequestMapping(method = RequestMethod.GET)
#ResponseBody
public List<Country> getListOfCountries() {
return countryService.listAll();
}
It displays a json view of the object but if the service return null, then I want to display an error message, Any suggestions pls?
First of all, even if this does not directly answer the question, your objects should never ever return null instead of empty collections - you can find the reasoning in Effective Java 2nd Edition, Item 43 / p.201
So, if the situation when no countries were found is normal it must be processed by the client JS code that will check the count and display the respective message.
If something has gone wrong you can throw an exception(as Biju has pointed out +1) - I believe that it's the service who should throw the exception because it knows the reason why it happened, and not to return null anyway.
I'd like to add that in Spring 3.2(in pre Spring 3.2 returning response body is complicated) you can set an #ExceptionHandler that will both return JSON and set the HTTP status code which can be later processed by the client. I think that returning a custom JSON response with some error code is most optimal here.
#RequestMapping("/test")
#ResponseBody
public List<Country> getListOfCountries() {
//assuming that your service throws new NoCountriesFoundException();
//when something goes wrong
return countryService.listAll();
}
#ExceptionHandler(NoCountriesFoundException.class)
ResponseEntity<String> test() {
return new ResponseEntity<String>(
"We are sorry, our server does not know any countries yet.",
HttpStatus.I_AM_A_TEAPOT );
}
Then in the JS code, you can do specific processing depending on the returned status code.
Also, to avoid declaration of the same #ExceptionHandler in different controllers, in Spring 3.2 you can put #ExceptionHandler inside a #ControllerAdvice annotated class.
For details, see http://static.springsource.org/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-exceptionhandlers and http://www.springsource.org/node/3738 for 3.2 specific things
You have a couple of options I think:
If you return a null back, it will be returned as an empty string "", you can probably look for that and handle it.
Return a wrapper type on top of your list, this way if the wrapped list is null something like this will be returned back to the client {"countries":null} which can be more easily handled at the javascript end.
Throw an exception, which will propagate as a 500 status code back to the client, you can then have an error handler on the javascript side to handle this scenario.

MVC 3 + REST return custom http error?

In my application I am trying to get it so that when a REST api call is made, if there is an error that it return a proper status code then either Json or Xml in the body of the response.
So 400: { 'ErrorCode': '400', 'Reason' : 'You did something wrong..' }
or 400: <Error><ErrorCode>400</ErrorCode><Reason>You did something wrong</Reason></Error>
However I can't seem to find how to set the status and body to make this happen. Using fiddler inspect whats being passed back and fourth I've found that if I return a normal ActionResult then I can return the body message ok but the status is 200. If I use HttpException then I can set the status code but the body message is returned as a large html document. I've tried using HttpStatusCodeResult but that just seems to fail and return a 302.
I'm a bit stumped.
Try Response.StatusCode = (int)HttpStatusCode.BadRequest; in your action method. Check out this article at develoq for a short tutorial: http://develoq.net/2011/returning-a-body-content-with-400-http-status-code/
Web API can handle this in various ways, but if you want to stick to ASP.NET MVC then use the code below:
Response.StatusCode = 500;
Response.TrySkipIisCustomErrors = true;
return Content("Error description goes here.", "text/plain");
Check out MVC 4 Beta, there is a new feature called Web API that will help you solve this issue.

Resources