【问题标题】:Play Framework, REST, Routes, and ControllersPlay 框架、REST、路由和控制器
【发布时间】:2014-01-17 15:17:43
【问题描述】:

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

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

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

【问题讨论】:

    标签: scala rest playframework


    【解决方案1】:

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

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

    第二个问题的答案取决于您是打算仅更新地址还是将始终更新整个用户。例如,您可以拥有一个包含所有用户详细信息和地址的巨大表单的网页,然后通过一个 HTTP 请求将其全部保存。

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

    【讨论】:

    • 是的...但是 RESTful URL 不应包含动词,而只能包含标识资源的名词。
    • 我不会那么严格,因为最终结果是一样的。您通过他的电子邮件地址获得用户。但是如果你真的不想在 URL 中有动词,那么有两个 URL GET /users controllers.users.find(email: Option[String])GET /user/:userId controllers.users.get(userId)
    【解决方案2】:

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

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

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

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

    很明显 user 是有趣的资源,而不是 email(注意我使用 email 你使用 address 以区别于我心中的物理地址)。我的路线看起来像users/:userId/emails/,就像您本质上一样,并在Users 控制器中管理它们。我认为没有任何理由——无论是从软件工程的角度还是意识形态的 REST 角度——增加额外类的开销。

    【讨论】:

    • 第一个答案:你的提议很好。 Robin Green 建议的选项是什么,即让控制器确定输入是 ID 还是电子邮件?第二个答案:你说的非常正确......也许我在可能的问题中不清楚:-)功能问题对我来说很清楚,即我希望用户能够添加他/她想要的任意数量的地址,但在注册时不是必须的(POST users/:userId/addressses)。我的困境是如何组织控制器:controllers.Users.addAddress vs controllers.Addresses.create。
    • 查看我的编辑。在我的脑海中没有明显的科学或客观答案,但更多的是实用的软件工程视角。
    • 好的,我明白了......无论如何,第二个问题可能是关于物理地址......而不是电子邮件(参见我帖子中的示例)。无论如何,感谢您提供宝贵的 cmets :-)
    【解决方案3】:

    以下内容不起作用,因为它与 GET users/:userId 冲突

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

    我是否应该获取一个用户,将新地址添加到 User.addresses,然后使用 PUT 更新用户?

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

    【讨论】:

    • 是的.. 我可以用这样的正则表达式修改路由: GET /users/$email/ controllers.users.findByEmail(email )。关于我的第二个问题......我更多地谈论的是设计(一个控制器与两个控制器 [一个用于用户,另一个用于地址]。
    • 路线的有趣想法。虽然看起来不太可读,但我个人更喜欢有一条路线并在控制器中进行区分。
    猜你喜欢
    • 2015-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-02
    • 1970-01-01
    • 1970-01-01
    • 2018-09-30
    相关资源
    最近更新 更多