我正在构建一个API,并且正在努力处理发布和更新资源的最佳方法。此时,用户将使用XML将数据发布到产品资源。我根据xsd文件验证了这个XML。这很有效,但意味着想要更新一个字段的用户必须发布与产品相关的所有字段。这是预期的,还是应该以其他方式做到这一点?
我有另一个资源需要“status”或“dispatched”更新,但只会更新一个或另一个,而不会同时更新。因此,我是否会以与产品资源相同的方式构建它,并且要求它们始终POST两个字段,即使只有一个字段会被更新或将它们作为两个单独的资源?
答案 0 :(得分:2)
您可以通过其他方式处理更新。第一个问题是您的客户如何知道如何更新资源?如果他们在带外接收信息,那么你就不会做REST。通过在带内包含更新信息,它使得如何更新显式,从而为您提供更大的自由度和灵活性。例如,product
资源可以表示如下
<product href="/products/123"
name="iPad 64GB + 4G"
price="829.00">
<description>It's cool, ya</description>
<update href="/products/123" method="PUT">
<name type="xs:string" cardinality="optional"/>
<price type="xs:decimal" cardinality="optional"/>
<description type="xs:string" cardinality="optional"/>
</update>
... you could have a delete form here as well ...
</person>
同时,products
集合可以表示为
<people href="/products">
... the first set of items in the collection and pagination links could go here ...
<create href="/product" method="POST">
<name type="xs:string" cardinality="required"/>
<price type="xs:decimal" cardinality="required"/>
<description type="xs:string" cardinality="required"/>
</create>
</people>
注意更新和创建之间参数的基数是如何不同的。
就PUT替换整个资源状态而言,请以这种方式考虑:当我更新product
并仅指定price
时,name
和description
默认为其现有值,然后更新整个资源。我们唯一需要做的就是在我们的媒体类型中明确定义这个逻辑。
根据您的描述,您目前可以按照
的方式表达某些内容<product href="/products/123"
name="iPad 64GB + 4G"
price="829.00">
<description>It's cool, ya</description>
<update href="/products/123" method="PUT">
<product type="my:product" cardinality="required"/>
</update>
... you could have a delete form here as well ...
</person>
<people href="/products">
... the first set of items in the collection and pagination links could go here ...
<create href="/product" method="POST">
<product type="my:product" cardinality="required"/>
</create>
</people>
这一点也不错,它只是更新的类型,因为你必须包括所有的字段。你觉得这是错的并且对此提出质疑是正确的。
此外,我强烈建议您不要使用XSD来验证请求。除非XSD设计得非常谨慎,否则它会在您的客户端和API之间产生紧密耦合,这将迫使您同时或以特定顺序(例如,服务器,然后客户端)更新这两者。请改为查看Schematron。
现在,就具有order
或status
详细信息的dispatch
而言,请将order
资源视为一个小型状态机。它可能看起来像这样:
Start ----> Received ----> Processed -------> Dispatched ------> End
| | ^
| V |
----------> Cancelled ------------------------------
因此,在创建订单时,会自动将其状态设置为已接收。从那里它可以被处理或取消,并且从处理它可以去发送或取消。我们的想法是通过资源中提供的表单和链接来表示转换。基于此,以下是我们如何为各种状态
表示order
收到(从客户的角度):
<order href="/orders/123" status="received">
... order details go here ...
<cancel href="/orders/123" method="delete"/>
</order>
收到(从员工的角度来看):
<order href="/orders/123" status="received">
... order details go here ...
<process href="/orders/123" method="put">
... whatever details need to be submitted at the same time ...
</process>
</order>
已处理(从客户的角度来看)
<order href="/orders/123" status="processed">
... order details go here ...
<cancel href="/orders/123" method="delete"/>
</order>
已处理(从员工的角度来看):
<order href="/orders/123" status="processed">
... order details go here ...
<dispatch href="/orders/123" method="POST">
<company type="xs:string" cardinality="required"/>
<con-note type="xs:string" cardinality="required"/>
<tracking type="xs:anyURI" cardinality="optional"/>
... whatever details need to be submitted at the same time ...
</dispatch>
</order>
调度(从客户和员工的角度来看)
<order href="/orders/123" status="dispatched">
... order details go here ...
<shipping-details href="/order/123/shipping">
</order>
取消(从客户和员工的角度来看)
<order href="/orders/123" status="cancelled">
... order details go here ...
</order>
根据权限将不同的状态转换呈现给不同的用户。员工无法取消订单,同样客户也无法处理或发送订单。此外,仅根据订单的当前状态显示允许的状态转换。
答案 1 :(得分:1)
使用POST,您可以灵活地定义为给定资源定义的状态。 POST可以是一种全能的方法。如果您使用的是PUT方法,那么您需要替换整个资源状态,因为HTTP规范将此定义为正确的行为。实际上,为状态创建单独的资源并使用自己的GET / POST / PUT / DELETE行为调度以表示您正在描述的用例可能是有意义的。