-
Notifications
You must be signed in to change notification settings - Fork 38.5k
Ease creating Location headers in REST controllers [SPR-8020] #12675
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Eugen Paraschiv commented This would indeed be a useful feature and a good step forward for first class REST support in Spring. As it stands now, the only way to do it is indeed to work with the low level request and response, which is not ideal. |
Rossen Stoyanchev commented Oliver, a For example the following prepares a URL based on the current request including the context path, and the literal part of the servlet mapping (assuming something like "/main/*"): String url =
ServletUriComponentsBuilder.fromServletMapping(request).path("/customers/{id}").build()
.expand(repository.findOne(id)).encode().toUriString(); This is available with 3.1.0.BUILD-SNAPSHOT. Please, give it a try! Section 16.7 "Building URIs" covers the subject and also there are test cases in UriComponentsTests, UriComponentBuilderTests, and ServletUriComponentBuilderTests. |
Rossen Stoyanchev commented With regards to Use of ReponseEntity is simple and unambiguous and suitable in this scenario. In combination with my previous comment it could look something like this: @RequestMapping(value = CUSTOMERS, method = RequestMethod.POST)
public ResponseEntity createCustomer(@RequestBody Customer customer, HttpServletRequest request) {
Customer result = repository.save(customer);
URI location =
ServletUriComponentsBuilder.fromServletMapping(request).path("/customers/{id}").build()
.expand(result.getId()).toUri();
HttpHeaders headers = new HttpHeaders();
headers.setLocation(location);
return new ResponseEntity(headers, HttpStatus.CREATED);
} You can also leave out the HttpServletRequest entirely, which relies on ThreadLocal access: @RequestMapping(value = CUSTOMERS, method = RequestMethod.POST)
public ResponseEntity createCustomer(@RequestBody Customer customer) {
Customer result = repository.save(customer);
URI location =
ServletUriComponentsBuilder.fromCurrentServletMapping().path("/customers/{id}").build()
.expand(result.getId()).toUri();
HttpHeaders headers = new HttpHeaders();
headers.setLocation(location);
return new ResponseEntity(headers, HttpStatus.CREATED);
} |
Mike Whittemore commented Perhaps this would be hiding too many details, but it may be useful to provide a builder that can streamline this sort of thing. For example something like the following:
For usage patterns that do not return
|
Oliver Drotbohm commented I essentially like the stage Rossen has brought this to already. I esp. like not needing to get the ….path("/customers/{id}").build().expand(result.getId()).toUri(); still deserves a shortcut of some kind. I wouldn't even mind just boiling the four method calls together to ….buildAndEncodePath("/customers/{id}", result.getId()); as I think esp. the intermediate |
Rossen Stoyanchev commented We can add support for a UriComponentsBuilder argument, which would be created via ServletUriComponentsBuilder.fromServletMapping(request) as well as add a buildAndEncode shortcut method. It would look like this: @RequestMapping(value = CUSTOMERS, method = RequestMethod.POST)
public ResponseEntity createCustomer(@RequestBody Customer customer, UriComponentsBuilder builder) {
Customer result = repository.save(customer);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(builder.path("/customers/{id}").buildAndExpand(result.getId()).toUri());
return new ResponseEntity(headers, HttpStatus.CREATED);
} Good enough? |
Oliver Drotbohm commented Looks great! (I think there's a closing parenthesis missing after ….getId()). |
Eugen Paraschiv commented The support for this seems to be coming along nicely, but still looks like it can be further improved. |
Eugen Paraschiv commented Sorry, it should be "update the headers of the RESPONSE without ... " above (unable to edit). |
Oliver Drotbohm opened SPR-8020 and commented
With it's annotation model Spring MVC provides a convenient way to write REST based server side components. Unfortunately creating fully-qualified URLs for the
Location
header (for POST requests especially) requires us to haveHttpServletRequest
andHttpServletResponse
in the controller methods signature just to hand it to a helper method to copy the static part of the request URL (everything up to the servlet context) into a String and piping it back to the response.So as
HttpHeaders
already has asetLocation(URI uri)
method, I wonder whether Spring MVC could simply "expand" this URI to prepend the path up to the servlet context in case the URI does not start with a protocol string. Beyond that, having a@ResponseHeaders
annotation which allows you to bind the response headers to a controller method parameter of typeHttpHeaders
would round of the support. This way a controller could look something like this:Affects: 3.0.5, 3.1 M1
Referenced from: commits 60ee0bb
3 votes, 5 watchers
The text was updated successfully, but these errors were encountered: