我已经阅读了一些有关RESTful API设计的有趣教程,其背后的概念非常清楚...但是现在让我们将其与Play一起实践。
假设我们要实现一个RESTful API,该API提供了与用户打交道的功能。让我们从模型开始。这是Address
类:
case class Address(
id: Int,
street: String,
zip: String,
city: String,
country: String
)
...这是
User
类:case class User(
id: Int,
email: String,
firstName: String,
lastName: String,
addresses: Array[Int]
// addresses: Array[Address] would this option be better?
)
...最后是路线:
# 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)
第一个问题是:如何通过电子邮件检索用户,使我的API投诉与REST规则保持一致?以下内容无效,因为它与
GET users/:userId
冲突:# Gets the user identified by the specified email address
GET /users/:email controllers.users.findByEmail(email)
到目前为止,我想到的两个选项是:
GET /users controllers.users.list(Option[email])
要么
GET /users/:email/xxx controllers.users.findByEmail(email)
其中
xxx
应该是一种虚拟资源。有什么建议吗?我的第二个也是最后一个问题是:我应该如何管理用户地址?我应该获取
User
,将新的Address
添加到User.addresses
,然后使用PUT更新User
吗?PUT /users/:userId controllers.users.update(userId)
...还是我应该创建一个特定的 Controller 来管理这样的用户地址?
POST /users/:userId/addresses/ controllers.addresses.create(userId)
我个人更喜欢第二种选择……但是也许有更好的选择。
最佳答案
第一个问题是:如何通过电子邮件检索用户,使我的API投诉与REST规则保持一致?
我想说的简单GET /users/email/:email controllers.users.findByEmail(email)
如果存在具有给定电子邮件的用户,则返回200,否则返回404。
我可以看到景点,但我会为@Robin搏击他的想法。从技术上讲这是可行的,但是由于我对REST的Identification of Resources元素的解释,它对我来说并不是REST风格的。另外,合并两个或多个标识符在服务器上消除歧义的可能性使我感到震惊,因为脆弱的代码最终将迫使我在周末工作,因为用户标识符会随着需求的变化而来去去–迫使我在和过度。我也可能因看到规范方法名称(如findByName
,findByEmail
等)而偏颇,但从未看到findByYourGuessIsAsGoodAsMine
。
我的第二个也是最后一个问题是:我应该如何管理用户地址?我应该获得一个用户,将新地址添加到User.addresses,然后使用PUT更新该用户吗?...还是应该创建一个特定的 Controller 来管理这样的用户地址?
显然,用户是有趣的资源,而不是电子邮件(请注意,我在使用电子邮件的地方使用地址来区分实际地址)。本质上,我的路线看起来像users/:userId/emails/
,并在Users
Controller 中进行管理。从软件工程角度或意识形态REST角度来看,我都没有理由增加额外的类的开销。