Return HTTP 204 on null with spring @RestController
Solution 1
Of course yes.
Option 1 :
@RestController
public class RepoController {
@RequestMapping(value = "/document/{id}", method = RequestMethod.GET)
public Object getDocument(@PathVariable long id, HttpServletResponse response) {
Object object = getObject();
if( null == object ){
response.setStatus( HttpStatus.SC_NO_CONTENT);
}
return object ;
}
}
Option 2 :
@RestController
public class RepoController {
@RequestMapping(value = "/document/{id}", method = RequestMethod.GET)
public Object getDocument(@PathVariable long id) {
Object object = getObject();
if ( null == object ){
return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
}
return object ;
}
}
Might have typos, but you get the concept.
Solution 2
You can use the @ResponseStatus annotation. This way you can have a void method and you don't have to build a ResponseEntity.
@DeleteMapping(value = HERO_MAPPING)
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void delete(@PathVariable Long heroId) {
heroService.delete(heroId);
}
BTW returning 200 when the object exists and 204 otherwise it's a bit unusual regarding API REST design. It's common to return a 404 (not found) when the requested object is not found. And this can be achieved using a ControllerAdvice.
In Spring REST it's better to handle Exceptions with a Exception handler instead of putting logic to decide the response status, etc. This is an example using the @ControllerAdvice annotation: http://www.jcombat.com/spring/exception-handling-in-spring-restful-web-service
Solution 3
I solved this problem with a filter. It's global and simple.
package your.package.filter;
import org.springframework.http.HttpStatus;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class NoContentFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
filterChain.doFilter(httpServletRequest, httpServletResponse);
if (httpServletResponse.getContentType() == null ||
httpServletResponse.getContentType().equals("")) {
httpServletResponse.setStatus(HttpStatus.NO_CONTENT.value());
}
}
}
and add the following in your web.xml
<filter>
<filter-name>restNoContentFilter</filter-name>
<filter-class>your.package.filter.NoContentFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>restNoContentFilter</filter-name>
<url-pattern>/rest/*</url-pattern>
</filter-mapping>
Solution 4
You can try this :
@RestController
public class RepoController {
@RequestMapping(value = "/document/{id}", method = RequestMethod.GET)
public ResponseEntity<String> getDocument(@PathVariable long id) {
if(noError) {
............
return new ResponseEntity<String>(HttpStatus.OK);
}
else {
return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
}
}
}
Uou need to change HttpStatus.BAD_REQUEST with the equivalent for 204 code status
Solution 5
Question is old but for those that needs a global answer and have Spring 4+, you can create a ResponseBodyAdvice that changes response code base on the controller response. The following exemple do it for all @RestController classes :
@ControllerAdvice(annotations = { RestController.class })
public class NullToNoContentResponseBodyAdvice
implements ResponseBodyAdvice<Object>
{
/**
* {@inheritDoc}
*/
@Override
public Object beforeBodyWrite(final Object p_responseBodyObject, final MethodParameter p_methodParameter,
final MediaType p_mediaType, final Class<? extends HttpMessageConverter<?>> p_class,
final ServerHttpRequest p_serverHttpRequest,
final ServerHttpResponse p_serverHttpResponse)
{
// ------------------------- DECLARE -------------------------- //
if (p_responseBodyObject == null)
{
p_serverHttpResponse.setStatusCode(HttpStatus.NO_CONTENT);
}
// Always return object unchanged or it will break response
return p_responseBodyObject;
}
/**
* {@inheritDoc}
*/
@Override
public boolean supports(final MethodParameter p_methodParameter, final Class<? extends HttpMessageConverter<?>> p_class)
{
return AbstractGenericHttpMessageConverter.class.isAssignableFrom(p_class);
}
}
user1606576
Updated on July 09, 2022Comments
-
user1606576 almost 2 years
This returns 200 OK with Content-Length: 0
@RestController public class RepoController { @RequestMapping(value = "/document/{id}", method = RequestMethod.GET) public Object getDocument(@PathVariable long id) { return null; } }
Simply put I'd like it to return 204 No Content on null.
Is there a way to force spring-mvc/rest to return 204 on null not 200? I dont want to change every rest method to return ResponseEntity or something like that, only map null to 204
-
Jean-François Beauchef about 7 yearsI think the OP wanted to return 200 on success, and 204 if he had null. You can put anything you want in the ResponseStatus. But the idea was to have multiple possible HTTP codes for one endpoint.
-
Karthik R about 7 yearsI agree with @Jean-FrançoisBeauchef. This is not the correct handling. This response status is applied irrespective of outcome (excluding exception scenario). The questioner wanted to know how to cater to condition of
null
-
spekdrum about 7 yearsSorry but I disagree. When using Spring REST it's better to handle exceptions and response codes with an Exception handler. This is an example jcombat.com/spring/…
-
Jean-François Beauchef about 7 years@spekdrum yes of course. You should use an exception handler to handle an exception. But this is not what the OP was asking for. He wanted to return 200 on a correct response with content, and 204 (which is also a correct response) when there is no content (or null, if you prefer). The OP doesn't even mention exceptions. And in Java (Spring or otherwise), exceptions should not be used for flow control.
-
Jean-François Beauchef about 7 yearsLook at the answers from mahieus and Marek Raszewski. You will understand what the OP was shooting for.
-
spekdrum about 7 yearsIm sorry but I have to say that what I'm suggesting is far different from using exceptions for flow control. Furthermore I still think it's a pretty valid answer. Not always we respond what the OP exactly asks, even more when we think that a better aproach can be done. I mean, when you call a GET method to a API it's common to asume that the element exists, throwing an exception otherwise.
-
Yan Khonski almost 7 years(HttpStatus.NO_CONTENT.value()) I copy-pasted the working solution +1 vote
-
mad_fox over 6 yearsCan you provide more detail on what is actually happening here. I'm trying to implement a similar solution. My idea is to automatically return 204 for all methods that have a void return type. It seems like this solution requires the method to take a HttpServletResponse as an input. I would like to avoid that.
-
Marek Raki over 6 yearsTry to use a static way to retrieve HttpServletResponse like here The rest should be the same but the @Pointcut should cover only void methods.
-
Stephan over 6 yearsVery nice solution
-
Shadow Man over 5 yearsSadly, neither of these options is a good (clean) solution. Ideally, your controller method would return a typed object rather than
Object
orResponseEntity
, and there would be some sort of intercepter that would notice that you were returning null, and set theNO_CONTENT
status code there (or was I just spoiled by Jersey and RESTEasy). -
user1606576 almost 4 yearsMaybe this is not the "correct" null handling, but this is what Jersey does, and this is the idiom we settled on using.
-
hurelhuyag almost 3 yearsI think this is the best answer. Thank you.