I've read some interesting tutorials about RESTful API design and the concepts behind it is quite clear... but let's put it into practice with Play now.
Suppose we want to implement a RESTful API that provides functionality for dealing with users. Let's start with the model. Here is the Address
class:
case class Address(
id: Int,
street: String,
zip: String,
city: String,
country: String
)
... here the User
class:
case class User(
id: Int,
email: String,
firstName: String,
lastName: String,
addresses: Array[Int]
// addresses: Array[Address] would this option be better?
)
... and finally the routes:
# Creates a new user
POST /users controllers.users.create
# Gets the user identified by the specified id
GET /users/:userId controllers.users.find(userId)
# Modifies the user identified by the specified id
PUT /users/:userId controllers.users.update(userId)
# Deletes the user identified by the specified id
DELETE /users/:userId controllers.users.delete(userId)
The first question is: how do I retrieve an user by email keeping my API complaint with the REST rules? The following wouldn't work because it conflicts with GET users/:userId
:
# Gets the user identified by the specified email address
GET /users/:email controllers.users.findByEmail(email)
The two options I've in mind so far are:
GET /users controllers.users.list(Option[email])
or
GET /users/:email/xxx controllers.users.findByEmail(email)
where xxx
should be a kind of virtual resource. Any suggestion for that?
My second and last question is: how should I manage user addresses? Should I get an User
, add the new Address
to User.addresses
, and then update the User
with PUT?
PUT /users/:userId controllers.users.update(userId)
... or should I create a specific controller for managing user addresses like this?
POST /users/:userId/addresses/ controllers.addresses.create(userId)
Personally I prefer the second option... but maybe there are better ones.
I would say simply GET /users/email/:email controllers.users.findByEmail(email)
which returns a 200 if a user with the given E-mail exists and a 404 otherwise.
I can see the attraction, but I would arm wrestle @Robin on his idea. It is technically feasible, but it doesn't feel RESTful to me because of my interpretation of the Identification of Resources element of REST. Also, merging two or more possibilities for identifiers to be disambiguated on the server strikes me as brittle code that will force me to work on weekends eventually because user identifiers will come and go as requirements change--forcing me to modify the controller endpoint over and over. I may also be biased by seeing canonical method names like findByName
, findByEmail
, etc. but never findByYourGuessIsAsGoodAsMine
.
It's clear that the user is the interesting resource rather than an email (Note I am using email where you use address to distinguish from physical address in my mind). My routes would look something like users/:userId/emails/
as you have essentially and to manage them in the Users
controller. I see no reason--from either software engineering perspective or a ideological REST perspective--to add the overhead of an extra class.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments