0

I have two type of entities: User and Resume. So my instinct said me to write two controllers.

UserController endpoints:

/users 
/users/{id} 
/users/{id}/resumes

ResumeController endpoints:

/resumes
/resumes/{id}
/resumes/searchBy[?criteria={criteria}]

User has a reference to resume, so to create one I do a POST to /users/{id}/resumes. Otherwise a POST to /resumes/{id_user}/ doesn't seems to be RESTful, isn't it?

Is it right to have these two controllers? although the first one has a reference of the service of the second controller:

class UserController {

    UserService userService;
    ResumeService resumeService;

}

Should I combine them?

  • 5
    Rest has nothing to do with implementation details. Neither with how your URIs looks like. From the client point of view, URIs are meaningless. – Laiv Jul 7 '17 at 16:35
  • @Laiv I reformulated my question – anat0lius Jul 10 '17 at 6:47
  • Nobody can say what"s right or not. You are looking for approval. Why do you need strangers approving your decisions? The only answer I could give is that your design leaks on consistency. You said that resumes must be related to a user and here we have a ResumeService to skip such business rule :-) – Laiv Jul 10 '17 at 6:56
  • @Laiv that was a typo. It is related but user referencing it and not otherwise: user -> resume – anat0lius Jul 10 '17 at 7:03
  • Does your design allow consumers to get access to the resume directly? Should consumers have access to the resumes directly? Or should they retrieve the user first and ask then the user? That's the question. – Laiv Jul 10 '17 at 7:05
3

The question I think you need to answer for yourself is: Should your UserController handle resume creation?

Which is more of a separation of concerns issue.

When it comes to deciding what to name the different behaviors of your API you should understand the concept of The Uniform Interface. The basics can be understood (very loosely) as: you should use a standards based approach when designing an API. The link explains those standards quite well.

Here's my 2 cents. Assuming a Content-Type: application/json API

I would create a resume as a POST to /resume and require a json body object with a userId property. An error would be thrown if it wasn't provided and no action would be taken by the API. { ... "userId": 1234 ... other resume stuff } And for the response I would return the ResumeId which would be created in the database.

Ultimately, you know how your API should be consumed.

  • 2
    Separating out a resumes endpoint from the users endpoint will avoid problems down the road and allow each service to evolve independently, e.g. user data unrelated to resumes – John Scattergood Jul 9 '17 at 20:54
1

You could really model this either way. It seems pretty natural to me that /users/{id}/resumes would be used to CRUD user resumes and that /resumes would be a query-only endpoint. Nothing says that the API and database have to map one-to-one. Especially for queries, I usually find I need multiple representations of the data. It is often even worth it to maintain a separate view / table / data store to support the special needs of queries. For example full text search.

1

Note that these endpoints are equivalent:

/users/{id}/resumes
/resumes/searchBy?user_id={id}

Allowing you to separate the ResumeService from your UserController.

As you can see from the above, /users/{id}/resumes is actually a filter on the collection thus it makes more sense to post to the entire collection: /resumes.

  • Actually this is what I want, decouple ResumeService from UserController (adding userId field to Resume entity as @EdwinJackson pointed), but I dont know if I should because of business logic: think of resumes as a catalog, so "buying" a resume means getting the user personal information, which then can be contacted. So my initial idea was to not include on a resume any information that could directly identify the user. E.g: a "hacker" could get the user information if the resume has the user id. I still have a lot to learn and maybe I'm being too cautious. – anat0lius Jul 9 '17 at 16:11
  • The only information that is revealed is what you choose to reveal. All resumes have an owner so they all have a foreign key to a user. If you can buy resumes then you need to make the code for change of ownership. The only way someone can use ONLY a user's id maliciously is if you have gaping security holes somewhere else. – Jacob Hull Jul 9 '17 at 20:49
  • Ok, I guess I could protect /users of being used without authorization. I'm working with Spring Framework and I still have to take a look at Spring Security. In fact I could use userId field only for POSTs of resumes, without storing it to the entity. Leaving it one-directional relationship (user -> resume) as I wanted. – anat0lius Jul 10 '17 at 6:39
  • Then it will be necessary to add: /users/searchBy?resume_id={id} – anat0lius Jul 10 '17 at 7:13
  • 1
    This might be useful for you then: toptal.com/java/rest-security-with-jwt-spring-security-and-java – Jacob Hull Jul 10 '17 at 10:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.