Play框架,REST,路由和控制器

时间:2013-12-30 17:41:49

标签: scala rest playframework

我已经阅读了一些有关RESTful API设计的有趣教程,其背后的概念非常清楚......但现在让我们将它付诸实践。

假设我们想要实现一个RESTful 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)

...或者我应该创建一个特定的控制器来管理这样的用户地址吗?

POST   /users/:userId/addresses/  controllers.addresses.create(userId)

就个人而言,我更喜欢第二种选择......但也许有更好的选择。

3 个答案:

答案 0 :(得分:1)

从您的问题不清楚您是否要实施“获取”或“查找”。通常,“get”会返回404,如果有该电子邮件的用户不存在,但我希望“find”返回200而没有结果。我个人会用这个:

GET    /users/find          controllers.users.find(email: Option[String])

对第二个问题的回答取决于您是否计划仅更新地址,或者您将始终更新用户整体。例如,您可以拥有一个包含所有用户详细信息的大型表单的网页。地址,您可以使用一个HTTP请求保存所有内容。

或者另一种观点可能是地址是独立资源还是总是与用户一起使用(创建/读取/更新/删除)。

答案 1 :(得分:0)

  

以下操作无效,因为它与GET用户/:userId

冲突

如果您的用户ID永远不会是有效的电子邮件地址(在此版本的REST API的生命周期内!),它仍然可以工作,因此您的代码可以区分它们 - 这是您当前类型的情况。当然,如果你想在将来放松这个假设,你可以随时介绍一个新的REST API版本(例如,如果你想让用户id为任意字符串),或者如果你决定不喜欢组合这两种类型的查询这一点。

  

我应该获得用户,将新地址添加到User.addresses,然后使用PUT更新用户?

默认情况下,这不是交易性的。但是,如果您使用ETag,则可以拒绝用户更新,如果其他内容在此期间更改了用户。

答案 2 :(得分:0)

第一个问题是:如何通过电子邮件检索用户,并使用REST规则保留我的API投诉?

我只想说GET /users/email/:email controllers.users.findByEmail(email),如果存在给定电子邮件的用户存在,则返回200,否则返回404。

我可以看到这个吸引力,但是我会在他的想法上与@Robin搏斗。它在技术上是可行的,但由于我对REST的Identification of Resources元素的解释,它对我来说并不感觉。此外,合并两个或多个标识符在服务器上消除歧义的可能性使我感到脆弱的代码,这将迫使我最终在周末工作,因为用户标识符将随着需求的变化而变化 - 迫使我修改控制器端点和过度。我也可能会因为看到findByNamefindByEmail等规范方法名称而有所偏见,但从不findByYourGuessIsAsGoodAsMine

我的第二个也是最后一个问题是:我该如何管理用户地址?我应该获得一个用户,将新地址添加到User.addresses,然后用PUT更新用户?...还是应该创建一个特定的控制器来管理这样的用户地址?

很明显,用户是有趣的资源,而不是电子邮件(注意我使用电子邮件,您使用地址以区分我脑海中的物理地址)。我的路线看起来与users/:userId/emails/基本相似,并在Users控制器中管理它们。我认为没有理由 - 无论是从软件工程角度还是从思想上的REST角度 - 来增加额外课程的开销。