12

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.

1
  • 1
    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) Commented Oct 11, 2016 at 20:31

2 Answers 2

13

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.

Sign up to request clarification or add additional context in comments.

1 Comment

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
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.