2

I’m writing a web API server that serves three relevant types of resources: authors, groups and channels. Each channel must be owned by exactly one author or group, and access control is determined by the requesting user’s relationship to the author or group in question, so I planned on creating a URL structure like:

  1. GET /authors/{authorId} — view specific author
  2. POST /authors/{authorId}/channels — create a channel belonging to that author
  3. GET /authors/{authorId}/channels — list channels belonging to that author
  4. GET /authors/{authorId}/channels/{channelId} — view specific channel belonging to that author
  5. GET /groups/{groupId} — view specific group
  6. POST /groups/{groupId}/channels — create a channel belonging to that group
  7. GET /groups/{groupId}/channels — list channels belonging to that group
  8. GET /groups/{groupId}/channels/{channelId} — view specific channel belonging to that group

The finished server will have many more paths for dealing with authors, groups and channels; these are given as examples.

Is it reasonable to attempt to do this with three controllers (i.e. AuthorsController, GroupsController, ChannelsController) in Spring Web MVC? How would I wire them together with RequestMapping annotations? Is there a way to decompose these responsibilities that makes more sense in Spring Web MVC, but still preserves cohesion?

N.B. I have seen a similar question asked, but the question and answers all focused on the inner classes.

1 Answer 1

5

You should organize classes generally based on the "single responsibility principle": A class should do "one thing", whatever that is.

In this case, it seems like having a class such as AuthorController to handle the HTTP machinery for authors or groups generally would be fine. The mappings for such a controller would look something like this (Groovy for simplicity and using the DomainClassConverter):

@RequestMapping('/authors')
@RestController
class AuthorController {

    @RequestMapping('/{id}')
    Author singleResource(@PathVariable Author id) {
        id
    }
}

Now you have a requirement that seems like it has the same behavior in multiple classes, which sounds like a possible use for inheritance, but you also have an object Channel that can be owned by multiple sorts of owners, which sounds like a possible use for generics.

If the logic for channel management is identical between authors and groups, then I would suggest using an abstract class ChannelController<O extends ChannelOwner> to handle all of the /channel mappings; if it's different, then make ChannelController<O> an interface and just declare the mappings.

Note that if you're using Spring Security to handle authorization, @RequestMapping annotations are inherited when you override/implement an abstract method, but @PreAuthorize and similar are not, so the security annotations have to be copied onto the lowest-level implementing class. You should always use MockMvc to ensure that you receive the appropriate Forbidden response for disallowed access.

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

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.