Rest api输入模型太笼统了

时间:2018-03-23 14:17:53

标签: rest api-design

我有一个典型的Spring Boot Rest API来对用户对象进行crud操作。

Class User{
    long id
    String displayName
    String email
    String passwordHash
    String passwordSalt
    Instant passwordExpiryDate
    boolean locked
    Instant version (sql timestamp for optimistic locking)
}
  • POST users/:创建用户
  • GET users/{id}:获取用户详细信息
  • PUT users/{id}:更新用户名和电子邮件
  • PUT users/{id}/password:更新用户密码
  • PUT users/{id}/unlock:将锁定状态设置为false
  • DELETE users/{id}
困扰我的是我的完整模型User类目前用作输入或输出,即使只有一些属性很重要。一些例子:

  • POST users/:您不需要提供ID,密码salt / hash或版本,而是生成它们。
  • GET users/{id}:无需返回id,请求者已经知道了。
  • PUT users/{id}:只需要一个新的电子邮件,名称和版本。
  • PUT users/{id}/password:只需要一个新密码和版本
  • PUT users/{id}/unlock:只需要版本

为了应对这种情况,我开始创建几个"请求"类:

  • NewUserDetails
  • UserWithoutId
  • UserWithOnlyPassword
  • UserWithOnlyPersonalDetails
  • UserVersion

这确保我的输入和输出仅包含所需的内容,并且不必读取任何文档以了解哪些属性是强制/使用的。缺点是它很愚蠢,因为它们都代表同一个实体,只是它的不同方面。此外,任何验证(我使用javax约束注释)都会多次声明。

我正在考虑删除所有请求主体,而是使用requestparams(查询参数)来仅提供必要的详细信息,但这会导致我在没有请求主体的情况下进行放置和发布操作。

对于api的客户端和内部结构,似乎没有解决方案。此API设计的最佳实践是什么?

2 个答案:

答案 0 :(得分:1)

我强烈建议您为Web API创建模型,而不是公开域(或持久性)模型,从而对API生成和使用的数据进行细粒度控制。

域(或持久性)模型很复杂,通常包含您不希望(或不必)公开的关系和属性。随着时间的推移,字段可能会添加到您的域模型,删除,重命名,修改等等。 如果您公开此类模型,您可能会发现很难在不破坏客户的情况下编排多个版本的API。

通过引入映射框架,您当然可以减少将API模型映射到域模型/从域模型映射的样板代码。

应该对服务层中的域模型执行验证。但是,没有什么可以阻止您对控制器层中的Web API模型执行某种级别的验证。

相关:answer已解决类似主题。

答案 1 :(得分:0)

我认为为每个操作创建不同的类是错误的,因为业务逻辑围绕同一个实体运行。对所有操作使用相同的对象本身(域对象模型)。您可以根据此类创建不同的验证。