Issue
I'm confused as what is the best preference for singleton resource. I want to have endpoint which has user id as:
/users/{id}
But I also want username
as parameter:
/users/{username}
I'm using Spring MVC (via Spring Boot) and it says the 2 endpoints are in conflict. So I decided to the first for retrieving singleton resource for users. But in order for the client to still use username as parameter, I added username as query parameter for the collection resource of users:
/users?username=<username>
In my repository
and service
layers, the return is Optional<User>
, i.e. it's either empty
or one user
result. But in the controller
, I wrap this in a list
, either empty or one, to make it consistent with the return of /users
as list.
Is this reasonable design? or is there any better design? Thanks.
Solution
Basically, you have two options:
- You either have two separate endpoints, for example,
/users/byId/{id}
and/users/byName/{username}
each mapped to a different controller method
class UserController {
@GetMapping("/byId/{id}")
Optional<User> findById(@PathVariable("id") String id){
...
}
@GetMapping("/byName/{username}")
Optional<User> findByUsername(@PathVariable("username") String username){
...
}
}
- Or one endpoint
/users/{id-or-name}
and you make the union query, so:findAllByIdOrName()
I tend to say that it's cleaner and more efficient to do it in separate endpoints.
Edit
The RESTful convention would mean that you have 2 endpoints:
@GetMapping("/{id}")
Optional<User> findById(@PathVariable("id") String id){
...
}
@GetMapping("/")
List<User> findUsers(@RequestParam("username") String username){
// if username is not empty, filter users
// we could also filter with other user properties according to specs
...
}
Anything other than such would be already deviating from the conventions.
Answered By - Ahmed Sayed
Answer Checked By - Katrina (JavaFixing Volunteer)