Spring Boot REST path mapping

14,923

Solution 1

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.

Solution 2

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

Share:
14,923
comprex
Author by

comprex

Updated on June 12, 2022

Comments

  • comprex
    comprex almost 2 years

    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.

  • blurfus
    blurfus over 7 years
    I'd even suggest that the friendship controller's mapping should be @RequestMapping("/user/{id}/friendship") and then all the other mappings are simplified into /code