I'm just thinking, what is the best practice to create PATH mapping for rest service. Let's say we have following paths:
/users POST
/users/1 PATCH, GET
/users/1/contacts GET, POST
/users/1/contacts/1 GET, PATCH
The question is - what is the best practice to create controllers. For example we have UserController where we technically could put all these mappings. Or - we should create seperate controllers (UserController, ContactsController). f.e UserController below, if we put everything under.
@RequestMapping("users")
@RestController
public class UserController {
@RequestMapping(method = RequestMethod.POST)
public ResponseEntity<Void> createUser() {}
@RequestMapping(method = RequestMethod.GET)
public User getUser() {}
@RequestMapping(value = "{id}/contacts", method = RequestMethod.GET)
public List<Contact> getContacts() {}
@RequestMapping(value = "{id}/contacts", method = RequestMethod.POST)
public ResponseEntity<Void> createContact() {}
.....
}
And if we create separate controllers, how paths should be organized then? Probably it's a silly question, but i will be glad, if someone could share experience.
The REST application follows the REST architectural approach. We use the REST application for developing and designing networked applications. It generates the HTTP request that performs CRUD operations on the data. Usually, it returns data in JSON or XML format.
annotation. RequestMapping annotation is used to map web requests onto specific handler classes and/or handler methods. @RequestMapping can be applied to the controller class as well as methods.
@RequestMapping is used at the class level while @GetMapping is used to connect the methods. This is also an important Spring MVC interview question to knowing how and when to use both RequestMapping and GetMapping is crucial for Java developers.
We can annotate classic controllers with the @Controller annotation. This is simply a specialization of the @Component class, which allows us to auto-detect implementation classes through the classpath scanning. We typically use @Controller in combination with a @RequestMapping annotation for request handling methods.
Lets suggest that number of entities related to User will increase in future. So it obvious that it is better to split it according to entities:
UserController -> UserService -> UserRepository,
ContactController -> ContactService -> ContactRepository,
FriendshipController -> FriendshipService -> FriendshipRepository
From my experience, User Controller
@RestController
@RequestMapping("/user")
public class UserController extends AbstractController {
...
@RequestMapping(method = RequestMethod.POST)
public ResponseEntity<?> createUser(@RequestHeader("X-Auth-Token") Optional<String> @RequestBody User user) {
...
@RequestMapping(method = RequestMethod.GET)
public ResponseEntity<?> listUsers(@RequestHeader("X-Auth-Token") Optional<String> authToken) {
...
related to user scope Friendship controller:
@RestController
@RequestMapping("/user/{id}")
public class FriendshipController extends AbstractController {
...
@RequestMapping(value = "/friendship/code", method = RequestMethod.POST)
public ResponseEntity<?> generateCodeForUser(@PathVariable("id") long id) {
...
@RequestMapping(value = "/friendship/code", method = RequestMethod.GET)
public ResponseEntity<?> retrieveCodeForUser(@PathVariable("id") long id) {
...
Not sure it is axiom, but help me organize my code.
I am a fan for separate controllers as they remove coupling between Users
and Contacts
(for example) - what if later you want to use Contacts
in a separate context? (i.e. independent of the User
they belong to)
If they are separated, the paths would look very similar to what you have:
Users
/users GET, POST
/users/{user-id} PATCH, GET
Contacts
/contacts GET, POST
/contacts/{contact-id} GET, PATCH
If there is a dependency between Contacts
and Users
(and in this case, it looks like there is one), you can have it like this:
/contacts/for-user/{user-id} GET, POST
/contacts/for-user/{user-id}/{contact-id} GET, PATCH
This allows you to add contacts to other things (not just users) and users to other contexts (regardless of their contacts)
For example, Users of a coffee maker
/coffee-maker/users GET
Or if the coffee maker fails, who do we contact for repair?
/coffee-maker/contacts GET
Probably a contact for a coffee maker repair is also a User (but they don't have to be)
One more thing, you can turn it around and say that a contact is for an appliance (i.e. a coffee maker)
/contact/for-appliance/{appliance-id} GET
My point being that if you decouple the contacts from the users, you can assign contacts to other entities instead of forcing the relationship to be User -> Contacts
- unless, of course, you don't want to decouple them because of business rules or some reason
In any case, beware that there are many ways of doing the mapping
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With