
I never thought creating customized http status codes would forces me to start an own sample project.
Some time ago I wanted to return customized http codes for rest resources in one of my sample projects. I started searching the web and found amongst many results some interesting such as this and that this and that . Although those websites contain detailed information, I wanted to dive deep into the subject and decided to code my own piece of code. I decided to use spring 3.2 as base of the resulting project.
Two ways of returning http status codes are implemented in the code:
- returning a ResponseEntity
- throwing an Exception
(both in the controller class of the sample project) .
Returning a ResponseEntity instance is quite easy. There is a list of several constructors you can choose from.
This code snippet shows two different constructor calls:
@RequestMapping(value = "/{itemID}", method = RequestMethod.PUT, produces="application/json")
public
@ResponseBody
ResponseEntity addItem(@PathVariable final String itemID, @RequestBody final Item item, HttpServletRequest request ) {
RESTItem inserted = null;
try{
inserted = itemService.insertItem(itemID, item);
}catch(ItemAlreadyExistsException iaee){
HttpHeaders responseHeaders = new HttpHeaders();
ResponseEntity re;
try{
responseHeaders.setLocation(new URI(request.getRequestURL().toString()));
re = new ResponseEntity(responseHeaders, HttpStatus.SEE_OTHER);
}catch (URISyntaxException urise){
log.error("URISyntaxException: " + urise + " n");
re = new ResponseEntity(HttpStatus.SEE_OTHER);
}
return re;
}
return new ResponseEntity(HttpStatus.CREATED);
}
The other approach is throwing an Exception.
@RequestMapping(value = "/{itemID}", method = RequestMethod.POST, produces="application/json")
public
@ResponseBody
RESTItem udpateItem(@PathVariable final String itemID, @RequestBody final Item item) {
RESTItem updated = itemService.updateItemByExternalID(itemID, item.getDescription(), item.getLabel());
if (null == updated) {
throw new BadRequestException();
}
return updated;
}
The exception class should extend RuntimeException and utilize spring’s @ResponseStatus annotation.
This annotation allows you to define the http code that is produced once the exception is thrown.
@ResponseStatus( value = HttpStatus.BAD_REQUEST )
public class BadRequestException extends RuntimeException{
....

The other classes in this sample project follow spring’s proposed mvc structure. My deployment uses maven’s tomcat7 plugin ( mvn tomcat7:(re)/(un)deploy ). This way the application is available via localhost on a local machine.
Often I used Poster for smoke test – so I did for this sample. One interesting detail about Poster is that it follows redirects. The addItem method showed above returns a SEE_OTHER http code including a location header if the item already exists. If the location header is followed with a get request that produces a 200/OK answer (see screenshot “PUT response – Poster” for details). Also the catalina.out log points to a 303 followed by a get request:
16962 [http-bio-8080-exec-21] DEBUG ItemController.java, addItem, 61 - e: info.lotharschulz.item.model.data.exception.ItemAlreadyExistsException: RESTItem already exists.
16963 [http-bio-8080-exec-21] DEBUG ItemController.java, addItem, 71 - re:
......
16969 [http-bio-8080-exec-30] DEBUG ItemController.java, getItem, 36 - RESTItem{externalID=id123,description=description,label=label}
16985 [http-bio-8080-exec-30] DEBUG AbstractMessageConverterMethodProcessor.java, writeWithMessageConverters, 150 - Written [RESTItem{externalID=id123,description=description,label=label}] as "application/json" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter@7326cbb1]
...
Postman, another tool to test (RESTful) APIs shows the same follow redirection behaviour.

Automated test are not included in the project ( yet ), however one tasks would be to check the SEE_OTHER status code rather then the redirected url status code.
You can find the sample code on github: https://github.com/lotharschulz/customHTTPcodes/tree/v0.1.
update
- screenshots and urls updated due to new branches and tags in the underlying github project
- travis ci badge:
- codacy badge:
Leave a Reply