【问题标题】:Object naming conventions for both REST and databaseREST 和数据库的对象命名约定
【发布时间】:2020-08-18 22:34:57
【问题描述】:

在使用 Java 中的 REST API 构建 CRUD 应用程序时,我一直在重新发明轮子,并且我正在寻找某种可以应用的标准。

让我们举个例子。假设我有一个“用户”表和这些 REST 端点:

GET  /users/{user_id} // returns a user
POST /users           // creates a user
PUT  /users/{user_id} // updates a user

在每个方法中,我必须选择、插入或更新数据库中的用户。

对于六个操作中的每一个(3 个用于 REST,3 个用于数据库),对于通过 REST 传入或发送到数据库的“用户”POJO,我需要一组不同的属性。

例如,在 REST 方面,创建用户时,我不需要 user_id(因为它是由数据库创建的),但我确实需要密码。获取用户时,我确实想要 user_id,但我不想将密码返回给客户端。更新用户时,我可能希望省略一些字段,因为它们是只读的(例如用户名或创建日期)。

在数据库方面,我可能需要不会在 REST API 中传回的不同字段,例如“is_approved”或“some_secret”。而且我经常需要创建派生字段,例如“password_hash”。

所以,正如我所说,同一事物的六种不同表示形式。在 Java 中,我通过创建六个不同的 POJO 类来做到这一点。它并不总是需要那么多独特的课程,但有时会。

在 REST API 中,我不想对所有端点使用相同的类而只是忽略某些字段,因为此类会传递给我们的 API 文档工具,并且其属性会被发布。

这六个类有什么标准的命名约定吗?

对于 REST,过去我使用过 CreateUser、GetUser 和 UpdateUser。我不喜欢这些名字,因为它们是动词,应该是名词。

UserForCreation 和 UserForUpdate 很尴尬。 NewUser 和 ModifiedUser 可能很好,但我不知道如何为 GET 调用用户。

我还需要另外一整套数据库端的名称。

这种事情肯定有一个标准或约定。有人知道是什么吗?

【问题讨论】:

  • 只比CreateUserGetUserUpdateUser略好,并借鉴了六边形架构:CreateUser[Request|Response]GetUser[Request|Response]UpdateUser[Request|Response]
  • 哦,我喜欢这个。 @图灵85
  • 把评论变成答案 =)

标签: java api rest design-patterns


【解决方案1】:

我认为您通常有正确的想法,为每个请求和响应设置特定对象;但是,根据 API 的设计,您只需要一个 User 类。您可以使用构建器抽象出创建逻辑(例如生成用户 ID),并将请求对象传递到位于 REST 端和数据库之间的DAO。 DAO 将简单地接受请求、检索用户数据、构建并返回 User 对象。

一旦创建了用户对象,它就可以用来创建响应对象,这些对象将被序列化并放入响应数据中。在这里编写两个用户类(例如UserInternalUser)可能是一个好主意,以更明确地说明哪些数据将暴露给客户端,特别是如果客户端是在同一个库中编写的API。您无法实现额外的InternalUser 并在响应对象构建器、工厂或构造器中处理字段过滤;但是,如果客户端是在同一个库中编写的,则可能会泄露敏感或必要的信息。

您可能想查看Swagger 文件。该标准提供了一个很好的 REST Api 规范,该规范非常简单,并提供了一种模板化 API 结构的好方法,即使它们最终看起来像 json 或 xml 的墙。

tl;博士 (根据@Turing85的建议

  • 创建用户[请求|响应]
  • GetUser[请求|响应]
  • UpdateUser[请求|响应]
  • 用户
  • 内部用户

【讨论】:

    【解决方案2】:

    这种方法是由HexagonalArchitecture/Clean Architecture/Ports and Adapters借用/启发的。由于我们已经清楚地分离了 DTO 和业务对象,因此我们非常接近上述架构。在 Clean Architecture 中,Bob 大叔谈到了“用例”。每个用例都有一些输入和一些输出。我们可以将输入想象为提供给用例的请求,而将输出想象为对给定请求的响应。因此,对于User 的业务实体和creategetupdate 的用例,我建议使用以下命名模式:

    <use-case><Business-entity>[Request|Response]
    

    对于给定的示例,这意味着我们创建类

    • CreateUserRequest, CreateUserResponse
    • GetUserRequest, GetUserResponse
    • UpdateUserRequest, UpdateUserResponse

    更重要的是:对于像CreateUpdate这样的复杂操作,我们可以提取公共字段并将它们放在超类中(如果Java只有多重继承,我们可以使用mixins......),留下实际用例请求仅包含我们真正需要的数据来定义。在许多情况下,响应是相同的,因此有一个共同的UserResponse-class 而不是许多不同的响应是有意义的。这提供了一致的 API 响应的额外好处,例如如果想要返回用户列表,可以返回List&lt;UserResponse&gt;(可能还有一些分页信息)。

    【讨论】:

      猜你喜欢
      • 2011-11-19
      • 2010-12-16
      • 1970-01-01
      • 2014-11-13
      • 1970-01-01
      • 1970-01-01
      • 2010-09-05
      • 1970-01-01
      相关资源
      最近更新 更多