Rest 休息-是否将ID放入身体?

Rest 休息-是否将ID放入身体?,rest,Rest,假设我想为人们提供一个RESTful资源,客户机可以在其中分配ID 一个人看起来像这样:{“id”:,“name”:“Jimmy”} 现在,客户端应该如何保存(或“放置”)它 PUT/person/UUID{“id”:,“name”:“Jimmy”}-现在我们有一个讨厌的重复,我们必须一直验证:身体中的id与路径中的id匹配吗 不对称代表: PUT/person/UUID{“name”:“Jimmy”} GET/person/UUID返回{“id”:,“name”:“Jimmy”} 正文中没

假设我想为人们提供一个RESTful资源,客户机可以在其中分配ID

一个人看起来像这样:
{“id”:,“name”:“Jimmy”}

现在,客户端应该如何保存(或“放置”)它

  • PUT/person/UUID{“id”:,“name”:“Jimmy”}
    -现在我们有一个讨厌的重复,我们必须一直验证:身体中的id与路径中的id匹配吗
  • 不对称代表:
    • PUT/person/UUID{“name”:“Jimmy”}
    • GET/person/UUID
      返回
      {“id”:,“name”:“Jimmy”}
  • 正文中没有ID-ID仅位于以下位置:
    • PUT/person/UUID{“name”:“Jimmy”}
    • GET/person/UUID
      返回
      {“name”:“Jimmy”}
  • 没有一种
    POST
    看起来是个好主意,因为ID是由客户机生成的

  • 常见的模式和解决方法是什么?仅在位置上使用ID似乎是最教条正确的方法,但它也使实际实现更加困难。

    您可能需要研究修补程序/放置请求类型

    修补程序请求用于部分更新资源,而在PUT请求中,您必须将整个资源发送到服务器上被覆盖的位置

    就url中的ID而言,我认为您应该始终拥有它,因为识别资源是一种标准做法。甚至StripeAPI也是这样工作的


    您可以使用修补程序请求更新服务器上ID为的资源,以识别该资源,但不更新实际ID。

    使用不同的读/写模型没有什么错:客户端可以编写一个资源表示,在服务器返回另一个表示后,可以在其中添加/计算元素(或者甚至是一种完全不同的表示——任何规范中都没有反对这一点的内容,唯一的要求是PUT应该创建或替换资源)

    因此,我选择(2)中的非对称解决方案,并在编写以下内容时避免服务器端的“讨厌的重复检查”:

    PUT /person/UUID {"name": "Jimmy"}
    
    GET /person/UUID returns {"id": <UUID>, "name": "Jimmy"}
    
    PUT/person/UUID{“name”:“Jimmy”}
    GET/person/UUID返回{“id”:,“name”:“Jimmy”}
    
    这个问题的一个解决方案涉及到“作为应用程序状态引擎的超文本”或“HATEOAS”这一令人困惑的概念这意味着REST响应包含可用的资源或要作为超链接执行的操作。使用此方法(这是REST最初概念的一部分),资源的唯一标识符/ID本身就是超链接。因此,例如,您可以有如下内容:

    GET /person/<UUID> {"person": {"location": "/person/<UUID>", "data": { "name": "Jimmy"}}}
    
    这样做的一个优点是,客户端不必知道服务器内部用户ID的表示形式。只要客户端有办法发现,ID可能会更改,甚至URL本身也可能会更改。例如,当获取一组人员时,您可以返回如下响应:

    GET /people
    { "people": [
        "/person/1",
        "/person/2"
      ]
    }
    
    (当然,您也可以根据应用程序的需要为每个人返回完整的person对象)


    使用这种方法,您更多地根据资源和位置来考虑对象,而更少地根据ID来考虑对象。因此,唯一标识符的内部表示与您的客户端逻辑分离。这就是REST背后的原始动力:创建比现有RPC系统更松散耦合的客户端-服务器体系结构之前,通过使用HTTP的功能。有关HATEOAS的更多信息,请查看以及此。

    这是以前提出的问题-讨论值得一看:

    这是一个很容易陷入争论的问题


    值得一提的是,我试着从一致的资源的角度来考虑,而不是在方法之间改变它们的设计。然而,从可用性的角度来看,最重要的是你在整个API中都是一致的!

    我从语义Web的角度来看这一点,因为这是实现rea的一个好方法l如我在中所述的REST一致性。从这个角度来看,毫无疑问可以选择选项(1),因为Web资源的ID(IRI)应该始终等于我可以用来查找/取消引用资源的URL。 我认为验证并不是很难实施,也不是计算上的问题,所以我不认为这是一个有效的理由去选择(2)。
    我认为选项(3.)并不是一个真正的选项,因为POST(新建)与PUT(更新/替换)具有不同的语义。

    使用不同的方法没有什么不好的。但我认为最好的方法是使用第二个的解决方案

     PUT /person/UUID {"name": "Jimmy"}
    
     GET /person/UUID returns {"id": <UUID>, "name": "Jimmy"}
    
    PUT/person/UUID{“name”:“Jimmy”}
    GET/person/UUID返回{“id”:,“name”:“Jimmy”}
    

    它主要以这种方式使用即使实体框架也使用这种技术当实体添加到dbContext中时,没有生成ID的类是通过实体框架中的引用生成的ID。

    在插入中,您不需要在URL中添加ID。这样,如果您在PUT中发送ID,您可能会被解释为更新更改主键

  • 插入:

    PUT /persons/ 
      {"id": 1, "name": "Jimmy"}
    HTTP/1.1 201 Created     
      {"id": 1, "name": "Jimmy", "other_field"="filled_by_server"}
    
    GET /persons/1
    
    HTTP/1.1 200 OK
      {"id": 1, "name": "Jimmy", "other_field"="filled_by_server"}  
    
  • 更新

    PUT /persons/1 
         {"id": "2", "name": "Jimmy Jr"} - 
    HTTP/1.1 200 OK
         {"id": "2", "name": "Jimmy Jr", "other_field"="filled_by_server"}
    
    GET /persons/2 
    
    HTTP/1.1 200 OK
         {"id": "2", "name": "Jimmy Jr", "other_field"="updated_by_server"}
    
  • 使用此标准并解决了返回插入或更新的对象以及指向新对象的链接时出现的一些问题。某些更新或插入可能包含一些将更改其他字段的业务逻辑


    您还将看到,在插入和更新之后,您可以避免get。

    如果它是一个公共API,您在回复时应该保守,但要自由地接受

    我的意思是,你应该同时支持1和2。我同意3没有意义

    支持1和2的方法是,如果请求正文中没有提供id,则从url获取id;如果请求正文中没有提供id,则验证它是否与url中的id匹配。如果两者不匹配,则返回
    PUT /persons/1 
         {"id": "2", "name": "Jimmy Jr"} - 
    HTTP/1.1 200 OK
         {"id": "2", "name": "Jimmy Jr", "other_field"="filled_by_server"}
    
    GET /persons/2 
    
    HTTP/1.1 200 OK
         {"id": "2", "name": "Jimmy Jr", "other_field"="updated_by_server"}
    
    POST    /device-management/devices      : Create a new device
    PUT     /device-management/devices/{id} : Update the device information identified by "id"
    PATCH   /device-management/devices/{id} : Partial-update the device information identified by "id"