java - 通过REST API处理ManyToOne实体集合的更新

标签 java spring hibernate rest

我正在努力思考通过REST API将集合更新到另一个资源的最佳方法,并且正在寻找有关其他人如何看待该过程的指导。

假设您与实体“父代”(一个)和“子代”(许多)具有多对一关系。我的想法是,您可以通过单个PUT端点处理更新父级的子级集合。这样,用于更新父级的子实体并将新的子实体添加到父级集合的端点通过单个端点发生。请求主体将包含一个子实体数组,并且端点本身将包含足够的信息以了解哪个父实体正在更新:

即PUT .../ parent /{uid}/ child

端点会告诉我们,uid为{uid}的父实体是被请求的父实体,并将其更新为子实体。

这种机制让人感觉有些奇怪。即,我必须以一种方式保留新实体,并以另一种方式更新它们。我的更新/保存操作最好分批执行,但是同时进行批保存和更新感到很奇怪。我必须同时做这两项,因为您无法更新新实体

有没有更好的方法可以做到这一点?关系是分层的,这意味着没有父级,子级资源就不存在。我仍然还希望能够批量发布/发布。

我可以揭露POST与PUT的区别(使用与上述相同的端点)。我有一个约束,使得子实体具有唯一的名称,因此对于具有现有名称的POST's新的子实体,POST将必须失败,并且当请求正文包含其名称的子实体时,PUT将必须失败不存在。这就是为什么我选择与单个端点共享操作的原因。

最佳答案

与ManyToOne打交道

关于正确处理ManyToOne关系,让我解释一下,如果我要尽可能多地遵守ReST原则,我将如何做。

嵌套资源

有几种表达关系的方法,一种是您建议使用路径层次结构的方法。您将需要以下端点:

  • /parents/
  • /parents/:id
  • /parents/:id/children
  • /parents/:id/children/:id

  • 这种选择可以更好地表达 child 无法独自生存的构图关系。

    一级资源

    如果要应用“超媒体”约束(应将其称为API ReSTful),则另一个选择如下:
  • /parents
  • /parents/:id
  • /childrens
  • /childrens/id

  • 创建子资源时,您将在请求的正文中包含指向具有适当rel类型的父资源的链接。例如,如果使用HAL:
    {
      ...
      ...,
      "_links": {
        "parent": { "href": "https://api.domain.com/parents/9283jdp92cn"}
      }
    }
    

    这种选择可以更好地表达弱关系或聚合关系,关系的两端可以彼此独立地存在。

    安全上下文

    还有第三种选择,我们应该将其视为特例。如果父资源是经过身份验证的主体,则可以将其隐式关联到另一资源。例如,如果父级是User域实体,并且是Photo集合的所有者,则您可能很想公开以下端点:
  • /users
  • /users/:id
  • /users/:id/photos
  • /users/:id/photos/:id

  • 鉴于只有User只能访问自己的Photo,这就足够了:
  • /photos
  • /photos/:id

  • 因为经过身份验证的User通过安全上下文可用于端点,并且可以隐式建立关系,而无需通过层次结构路径或其他方式明确表示它。

    其他注意事项

    从您的问题出发,我发现一些可能导致实现不良做法的信号。因此,这里有一些与您的帖子有关的原则,您应该尽可能遵循这些原则(务实)。
  • 每个资源都需要一个唯一的标识符,即ReST中的URI。正如您已经发现的那样,如果尝试按照问题中的设计来更新子实体,那么这样做失败将产生怪异的含义。
  • 您要成为Restful的API应该实现超媒体约束。如果您的资源ID是URI,则无论它们的服务器位置如何,都可以在它们之间创建完全合格且丰富的关联关系。
  • 标识符应该是不透明的。因此,切勿在URI的:id部分中使用相关数字或枚举。甚至不要让您的消费者尝试猜测可能暴露您不希望他们看到的内容的URI。安全是关键,但是不透明的ID是额外的。
  • 除非有充分的理由,否则标识符应由服务器而不是客户端生成。否则,您的ID不会变得不透明。
  • 作为经验法则:
  • 使用POST创建并返回201 Created。我喜欢用资源的主体来回应。并且不要忘记将URI包括到创建的资源中。
  • 读取GET并返回200 OK
  • 使用PUT修改整个资源。我喜欢与post保持一致,并使用200 OK返回更新的资源。
  • 使用DELETE删除并使用204 No Content进行响应。
  • 我很少使用PATCH进行部分更新。

  • 在大多数情况下,这可以使您满意。

    关于java - 通过REST API处理ManyToOne实体集合的更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40311989/

    相关文章:

    java - Android 为简单的自定义类使用依赖注入(inject)

    java - Spring MockMvc 返回 200 而不是 201。如何调试?

    spring - 服务器遇到了阻止它完成请求的意外情况

    java - 使用 SWT 在托盘图标上显示数字

    java - 使用保留关键字作为变量名创建 Java 对象

    java - Spring 和 Angular JS

    java - 无法使用 Hibernate 更新实体

    java - Hibernate查询一对一关系

    java图的邻接矩阵实现

    java - 如何在 Spring boot 中的 appication.properties 中启用 undertow 日志