如果我们已经创建了父子实体并且已经创建了父子实体,那么可以与REST API一起使用哪种HTTP方法?

时间:2019-05-07 13:56:47

标签: rest http

我查看了this PUT vs POST个问题以及其他关于stackoverflow的问题,并仔细研究了答案,发现:

  

如果服务器标识了资源地址,则使用POST

     

如果客户端知道资源的地址,请使用PUT。

如果我有一个独立实体,那么上面的方法就可以正常工作。例如,如果我有一个学生实体,那么我要招收一名新学生上学,我可以使用/api/schools/schools-name/student HTTP方法将REST端点创建为POST。但是一旦学生被录取并且我必须对此学生进行更改,我就可以使用Patch / PUT。

但就我而言,我有父母和子女的从属实体。首先,我使用POST创建父实体。现在,仅在创建父实体之后才创建子实体。为什么不能像创建父实体后一样一起创建子实体,也不能创建子实体,这是出于业务需求。

要注意的重要点是,父和子实体仅通过id列链接。因此,目前我用于创建子实体的网址是/api/entities/parent-entity-id。同样,在创建子实体时没有请求正文,因为用于创建的所有必需信息都存储在父实体中。

  

我的问题是,当我们创建   子实体或PUT,因为我正在更新父代的子代   已经创建的实体?

4 个答案:

答案 0 :(得分:1)

  

如问题中所述,没有用于创建子实体的请求主体。该API只是触发子实体的创建。父实体已经拥有所有信息。

如果您要向服务器发送unsafe请求,但该请求与其他任何HTTP方法的语义都不匹配,则应使用POST。

尤其是,如果message-body不是目标uri所标识资源的候选表示,则PUT超出范围。

  

PUT方法请求创建目标资源的状态或将其替换为请求消息有效负载中包含的表示形式定义的状态

答案 1 :(得分:0)

  

创建子实体时也没有请求正文,因为所有创建所需的信息都存储在父实体中。

因此,这与资源状态无关,因此与REST无关。

您不是要设置资源的新状态,因此应远离使用PUT。

答案 2 :(得分:0)

您正在创建一个新实例,因此对于先前创建的父实例,应在端点上使用POST方法。 示例:

POST /parent/<parent_id>/children/ 
BODY:
{"json with children data...."}

答案 3 :(得分:0)

首先,REST是一种体系结构样式,如果您需要将客户端与服务器分离,以允许在服务器端不断发展而又不冒客户端崩溃的风险,则可以使用REST。 REST不是一个工具集,您可以挑选出最合适的东西,而忽略其余的东西。它更多地是应用REST建议的所有步骤和约束,否则您将无法从中受益!对于简单的后端到前端通信,可能通常要付出很多努力,因为您通常都控制两端,但是,如果您不仅仅控制一端,那么实际上您可能会从这种设计中获得最大的收益。 / p>

REST在很大程度上依赖于标准化协议和媒体类型。交互模型非常类似于REST的堂兄可浏览Web。因此,适用于Web的相同概念也适用于REST。两者的核心思想应该始终是:服务器教客户如何做事,而客户只接受给定的内容,而不会试图从先前的交互或URI分析等推论得出进一步的知识。即在Web上,HTML表单用于允许客户端输入单击提交按钮后发送到服务器的某些输入。该Web表单中包含目标URI以及使用的方法,因此客户端实际上不必关心该事实。通过提供按钮元素,客户还具有隐含的知识,即可以单击按钮,并因此可以触发某些操作。现在,应在应用程序之间使用Web中使用的相同概念来相互交互。在这里,可以重用HTML表单,或者需要开发某些专门的媒体类型(例如,hal-forms)。通过内容类型协商,客户端和服务器实际上可以在表示形式格式上都支持,从而避免了互操作性问题。

许多“ REST开发人员”似乎遇到的一个常见问题是,考虑到REST端点返回的某些数据属于某些类型,即公司员工的数据或某些层次结构的项目。 Fielding声称,REST API不应将typed resources引入对客户有意义的东西,而应花费其几乎所有的描述性工作来定义用于表示资源和定义应用程序状态的媒体类型,或为现有标准媒体类型定义扩展关系名称和/或启用超文本的标记。

这里要提到的另一点是,URI默认情况下不继承父子关系,对此我已经在评论中做了一些说明。整个URI(包括任何路径,矩阵和/或查询参数)只是到资源的链接,可以视为用于缓存的键,以返回先前为该键存储的响应主体(= URI)。因此,客户端不应尝试从URI本身推断语义知识,而应仅使用针对此类URI返回的链接关系。这样一来,服务器就可以替换URI,而客户端仍可以根据返回URI的名称来调用它们。

由于URI本身不传达任何语义信息,因此它们无法真正表达自己的父子关系。我们人类倾向于将诸如/api/company/abc/employee/123之类的URI解释为表示编号为123的员工正在为公司abc工作,这可能是正确的,但也不必像解释的那样以前,URI缺乏表达此类内容的语义。只有利用一堆这样的URI才能创建这样的语义树。

  

但就我而言,我有父母和子女的从属实体。首先,我使用POST创建父实体。现在,仅在创建父实体之后才创建子实体。

如果仔细查看HTTP methods,可能会发现POST requests是根据资源自身的特定语义进行处理的,这意味着您可以执行此处必须要做的任何事情。这实际上是工具集中的瑞士军刀,如果其他方法不适合您的用例,则应使用此工具。

PUT,即指定用请求有效负载中提供的表示替换当前目标表示。但是,允许服务器验证PUT表示形式是否与服务器对目标资源的任何约束一致,并可能由于与某些约束的冲突而拒绝更新某个资源的请求。进一步允许PUT重新配置目标媒体类型以匹配更合适的表示,对接收到的有效载荷进行转换,以将有效载荷转换为目标资源中的一个匹配目标,或者通常拒绝有效载荷。

HTTP方法和URI都不能在父资源和子资源之间创建这种语义关系。但是,这就是链接关系的作用!链接是两个实体之间的边,这些边为这两个实体之间的关系的上下文命名。此类链接关系应为standardizedfollow common conventionsrepresent extension types as defined in RFC 5988 (Web linking),以促进其重用。但是,不幸的是,IANA并未直接指定parentchild链接关系。 up可用于在树中指代孩子到父母。但是,通过扩展机制,这相对容易获得,即http://api.acme.com/rel/parenthttp://api.acme.com/rel/child或类似的东西。

关于初始帖子引用部分的下一部分要讨论的是发生在父项创建语义与子项资源形成对比之前。除了pipelining section中没有概述的内容外,HTTP没有任何事务语义或对请求顺序的保证,这无论如何仅适用于安全方法。因此,HTTP不会对请求的处理做出任何承诺,因为它们可能根本无法到达服务器,或者响应由于某种原因而丢失。仅当客户端接收到201 Created响应,其中包含指向所创建资源的Location标头时,客户端才能确定已创建资源,并且仅根据规范,才允许客户端创建资源。进一步的子资源。

对于通用HTTP服务器,父级的创建请求以及创建子级资源的连续请求都是两个独特的请求,它将尝试独立实现。这是HTTP的无状态性质。如前所述,尽管如此,可能会对资源自身的约束进行某些验证,从而阻止了子代的创建。

  

要注意的重要点是,父和子实体仅通过id列链接。因此,目前我用于创建子实体的网址是/ api / entities / parent-entity-id。同样,在创建子实体时没有请求正文,因为用于创建的所有必需信息都存储在父实体中。

REST实际上并不关心您的域模型。您这里拥有的是/persons资源的经典示例,其中三个人可以通过单独的,独特的URI(例如/persons/alice/persons/bob/persons/joe)进行标识。如上所述,我们对这些端点中的任何一个端点本身及其返回的实际数据一无所知,您无法直接从URI推论出谁的父母(或任何URI实际上代表一个人)。从...开始)。通过链接关系,现在可以给出这样的上下文结构,说明Bob和Alice是Joe的父母,而Joe是Bob和Alice的孩子。

请注意,在上面的示例中,资源的实际内容对客户端而言并不重要。我们仍然不知道任何一个资源是否全部包含任何信息。我们所知道的是,有3种可用资源以某种方式相互链接。因此,如果您的系统的意图是仅表示此类关系,那么请继续。使用这些资源之间的链接,使客户可以在感兴趣的情况下查找这些关系。如果客户端对资源的详细信息感兴趣,无论如何它将向服务器发送对某种媒体类型集的请求。可发现性和探索是您在REST生态系统中要保证的两件事。

  

我的问题是,当我们创建子实体时,此方法应为POST还是在更新已创建的父实体的子项时为PUT?

AS POST是一种通用工具,如果其他方法不合适,则必须使用它,使用POST肯定没有错。如果仔细研究一下其他方法,您可能会发现它们具有不同的用途,即PUT的语义是将当前内容替换为请求有效负载中给定的内容。因此,它表示的用例与您实际想要的IMO不同。因此,您也应该坚持POST来生儿育女。

您希望在POST逻辑中应该做的事情是引入有意义的链接关系,这些链接关系为您提供了可以命名的“实体”之间的关系,这在整个答案中都希望如此。这样的操作还会产生副作用,使您也可以更新父资源,并引入一些从父指向孩子的链接。

尽管我想确保您了解REST的意图以及何时使用它,但该帖子可能已经比需要的更长。除非您确实需要一个需要诸如freedom for evolution故障稳健性对应用程序/系统运行数十年的支持之类的属性的系统,否则它们都将暴露您自己的RPC服务或直接公开数据模型可能更容易获得。