Reputation: 1874
We have a REST API, for some comments. Currently, the most interesting URIs are:
GET /products/1/comments // get all comments of product 1
GET /products/1/comments/5 // get the 5th comment of product 1
GET /products/1/comments/5/user // get the user of the 5th comment
GET /products/1/comments/latest // get the latest comment of product 1
GET /products/1/comments/latest/user // get the user of the latest comment
in addition, you can directly access comments
GET /comments/987 // get the comment with id 987
GET /comments/987/user // get the user of comment with id 987
so, we have two @RestController
:
@RestController
@RequestMapping("/products/{productId}")
public class ProductsCommentsResource {
@GetMapping(value = "/comments")
public ResponseEntity<?> getComments(@PathVariable Long productId){
// get all products...
}
@GetMapping(value = "/comments/{commentNr}")
public ResponseEntity<?> getComment(@PathVariable Long productId, @PathVaraible Long commentNr){
// get comment with number commentNr of product productId
}
@GetMapping(value = "/comments/{commentNr}/user")
public ResponseEntity<?> getCommentUser(@PathVariable Long productId, @PathVaraible Long commentNr){
// get the user of comment with commentNr of productId
}
@GetMapping(value = "/comments/latest")
public ResponseEntity<?> getLatestComment(@PathVariable Long productId){
// get latest commentNr and call getComment(productId, commentNr)
}
@GetMapping(value = "/comments/latest/user")
public ResponseEntity<?> getLatestCommentUser(@PathVariable Long productId){
// get latest commentNr and call getCommentUser(productId, commentNr)
}
}
@RestController
@RequestMapping("/comments")
public class CommentsResource {
@GetMapping(value = "/{commentId}")
public ResponseEntity<?> getComment(@PathVaraible Long commentId){
// get comment id commentId
}
@GetMapping(value = "/{commentId}/user")
public ResponseEntity<?> getCommentUser(@PathVaraible Long commendId){
// get the user of comment with id commentId
}
}
The latest
is therefore only a replacement-keyword for "get the last commentNr and call the corresponding method with this commentId"
This is just an excerpt and in addition to the user, a comment has about 30 sub-and sub-sub-resources (including methods POST, DELETE etc.). Therefore, we have more or less everything three times.
So, obviously, we need to improve this, to remove duplicate code etc.
The idea is to "encapsulate" the comments-resources and make it reusable by using the @RequestMapping
annotated at the class.
We thought about a mechnism like:
/products/1/comments/latest/user
is calledThus, we would need to have something that redirects
- /products/1/comments/latest[what ever]
to /comments/{commentId}[what ever]
- /products/1/comments/5[what ever]
also to /comments/{commentId}[what ever]
and /comments/{commentId} would be the only the implementation.
However, we did not find anything suitable in the spring docs...
Upvotes: 3
Views: 2371
Reputation: 14826
You could add additional URL path prefix in your controller's @RequestMapping
.
@RequestMapping(value = { "/products/{productId}", "/" })
This means that you can remove CommentsResource
controller and you'll be able to access the same resource at:
/products/1/comments/5
and at
/comments/5
For instance, here:
@GetMapping(value = "/comments/{commentNr}")
public ResponseEntity<?> getComment(@PathVariable Long productId, @PathVaraible Long commentNr){
// get comment with number commentNr of product productId
}
The obvious issue would be a productId
path variable. If you're using Java 8, that can be solved fairly easy by using Optional
:
@GetMapping(value = "/comments/{commentNr}")
public ResponseEntity<?> getComment(@PathVariable Optional<Long> productId, @PathVaraible Long commentNr){
// get comment with number commentNr of product productId
// Check whether productId exists
}
Upvotes: 5