Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring boot REST controller POST request handling

Using Spring Boot (v1.2.6.RELEASE), I need to accept POST requests for the Controller methods.

@RestController
@RequestMapping(value = "/myWebApp/signup")
public class RegController {

    @RequestMapping(value = "/registerFamily", method = { RequestMethod.POST  }, headers = {"Content-type=application/json"})
@ResponseBody
public FamilylResponse registerFamily(@RequestBody @Valid FamilyRequest familyRequest){

... }

When I send POST request from REST clients from Chrome/mozilla,the response comes as follows:

{"timestamp":1446008095543,"status":405,"error":"Method Not Allowed","exception":"org.springframework.web.HttpRequestMethodNotSupportedException","message":"Request method 'POST' not supported","path":"/myWebApp/signup/registerFamily"}

...

The stack trace is as follows:

  org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
at org.springframework.web.servlet.support.WebContentGenerator.checkAndPrepare(WebContentGenerator.java:273)
at org.springframework.web.servlet.support.WebContentGenerator.checkAndPrepare(WebContentGenerator.java:251)
at org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(ResourceHttpRequestHandler.java:207)
at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:51)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)  

Following the response of Spring: not accept POST request under mvc:resources? how to fix that,

I think some other sub class of WebContentGenerator, like WebContentInterceptor, RequestMappingHandlerAdapter should handle the requests for Controllers.

Also while running Junit tests, I found that the RequestMappingHandlerAdapter is handling those requests for Controllers.

But I'm yet to find how to configure this to accept POST requests as well?

Any other better solution should be more than welcome.

EDIT:

Tomcat uses WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter(a subclass of WebMvcConfigurerAdapter) and

WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter.addResourceHandlers(ResourceHandlerRegistry) does the following:

o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]

o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]

In junit, I have added an empty concrete child class of WebMvcConfigurerAdapter.

and WebMvcConfigurerAdapter.addResourceHandlers(ResourceHandlerRegistry) does nothing.

@Configuration
@EnableWebMvc
public class WebAppContext extends WebMvcConfigurerAdapter {}

@Configuration
@Import({ WebAppContext.class })
@PropertySource("classpath:application.properties")
public class ExampleApplicationContext { }


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {ExampleApplicationContext.class})
@WebAppConfiguration
public class RegControllerTest {  ... }   
like image 419
lab bhattacharjee Avatar asked Oct 28 '15 07:10

lab bhattacharjee


2 Answers

It's hard to say what's wrong, because your code seems fine. But I'll try to suggest some small changes, that may help to clarify situation.

At first, you don't need additional @ResponseBody annotations while you are using @RestController. From spring site:

Spring 4’s new @RestController annotation, which marks the class as a controller where every method returns a domain object instead of a view. It’s shorthand for @Controller and @ResponseBody rolled together.

Also, the problem may hiding under your headers requirement. If it is not specific, you can change it to consumes option. Try the snippet below.

@RequestMapping(value = "/api", method = RequestMethod.POST, 
                    consumes = "application/json", produces = "application/json")
like image 110
VadymVL Avatar answered Oct 28 '22 05:10

VadymVL


Based on spring doc, the headers attribute:

The headers of the mapped request, narrowing the primary mapping. Same format for any environment: a sequence of "My-Header=myValue" style expressions, with a request only mapped if each such header is found to have the given value. Expressions can be negated by using the "!=" operator, as in "My-Header!=myValue". "My-Header" style expressions are also supported, with such headers having to be present in the request (allowed to have any value). Finally, "!My-Header" style expressions indicate that the specified header is not supposed to be present in the request.

So, your POST request will be mapped correctly if and only if a Content-type header with application/json value is present. The better approach for limiting Content-Type would be consumes attribute. If you were using consumes attribute, in case of a invalid or missing Content-Type header, a 415 Unsupported Media Type would return, which more desirable.

like image 38
Ali Dehghani Avatar answered Oct 28 '22 05:10

Ali Dehghani