简体   繁体   English

REST设计 - 针对特定更新的PATCH

[英]REST Design - PATCH for a specific update

I have a resource which represents a set of physical devices. 我有一个代表一组物理设备的资源。

Calling GET v1/devices/ yields the following result: 调用GET v1/devices/产生以下结果:

[
  {
    "MacAddress": "DD-22-33-15-15-66",
    "Name": "Test Device",
    "State": "Approved"
  },
  {
    "MacAddress": "E5-21-56-44-11-B6",
    "CompanyId": "Another Test Device",
    "State": "Pending"
  }
]

A device has a state (an important attribute) which can only be pending or approved , and so the following GET requests are also available: 设备具有状态(重要属性),只能pendingapproved ,因此以下GET请求也可用:

  • GET v1/devices/pending : Retrieves all pending devices GET v1/devices/pending :检索所有待处理的设备
  • GET v1/devices/approved : Retrieves all approved devices GET v1/devices/approved :检索所有已批准的设备

You can also get an individual device from the resource using GET v1/devices/EF-55-33-44-54-61 您还可以使用GET v1/devices/EF-55-33-44-54-61从资源中获取单个设备

I now want to be able to update only the state of a device from Pending to Approved . 我现在希望能够仅将设备的状态从PendingApproved

Would the following PATCH call make sense? 以下PATCH调用是否有意义?

PATCH v1/devices/EF-55-33-44-54-61/approve

From some reading, it would seem the proper way to do it would be something like this: 从一些阅读,似乎正确的方式是这样的:

[
  {"replace": "/state", "value": "approved"}
]

But this seems too flexible for such a specific update. 但这对于这样一个特定的更新来说似乎太灵活了。 I never want other values to be updated and I also don't want the state to be changed in any other way. 我从不希望更新其他值,我也不希望以任何其他方式更改状态。

I would perform the PATCH against the URI of the object being patched: 我会针对正在修补的对象的URI执行PATCH:

PATCH v1/devices/EF-55-33-44-54-61

There is no convention saying that the PATCH method in your Web API Controller has to allow patching for all properties on the device object. 没有任何惯例说Web API控制器中的PATCH方法必须允许修补设备对象上的所有属性。 If you only support an update to that one property, that is OK. 如果您只支持对该属性的更新,那就没问题。

While the longer JSON above seems a bit excessive, it also means that if something changes later and you do need to PATCH more than one property, you now only need to update your controller to allow it and the JSON stays the same (albeit with potentially more than one replacement being done in a single call). 虽然上面较长的JSON看起来有点过分,但这也意味着如果以后某些内容发生变化并且您确实需要PATCH多个属性,那么现在只需要更新控制器以允许它并且JSON保持不变(尽管有可能)在一次通话中完成多次替换)。

First off, you shouldn't use this URL pattern to filter the returned devices. 首先,您不应使用此URL模式来过滤返回的设备。 You're using the pattern below, but IMHO, it's not the best approach here. 你正在使用下面的模式,但恕我直言,这不是最好的方法。

GET v1/devices/<approved|pending>

Instead, if you want to filter or limit the returned devices using as filter one or more of its attributes, you should use the QueryString like this: 相反,如果要使用过滤器的一个或多个属性过滤或限制返回的设备,则应使用如下的QueryString:

GET v1/devices?status=<approved|pending>

Remember that your URIs should address only resources and, in my opinion, "approved" isn't a resource. 请记住,您的URI应仅处理资源,在我看来,“已批准”不是资源。 In fact, it's a state of this resource. 实际上,这是该资源的状态。 In this case, use the QueryString to filter or limit the resources you want to work upon. 在这种情况下,使用QueryString过滤或限制您要处理的资源。 Moving on to your main question... 转到你的主要问题......

Would the following PATCH call make sense? 以下PATCH调用是否有意义? PATCH v1/devices/EF-55-33-44-54-61/approve PATCH v1 / devices / EF-55-33-44-54-61 / approve

Yes and no! 是的,不! :) You can use the same approach that Github uses. :)您可以使用Github使用的相同方法。 On Github, if you want to "star" a gist through their API, you must do a POST on the sub-resource "/gist/id/star". 在Github上,如果你想通过他们的API“点亮”一个要点,你必须在子资源“/ gist / id / star”上进行POST。 You may think of it as "I'm creating the sub-resource star". 您可能会将其视为“我正在创建子资源明星”。 If you want to "unstar" this gist, you must do a DELETE on "/gist/id/star" (I'm DELETING the sub-resource star from the main resource). 如果你想“解开”这个要点,你必须在“/ gist / id / star”上做一个DELETE(我正在从主要资源中删除子资源星)。

In your case, I'd do something like this: 在你的情况下,我会做这样的事情:

POST    v1/devices/EF-55-33-44-54-61/approval

You may think of it as "I'm creating the sub-resource approval". 您可能会将其视为“我正在创建子资源批准”。 Maybe it would have different states, like "approval date", "user who approved it"... 也许它会有不同的状态,如“批准日期”,“批准它的用户”......

DELETE v1/devices/EF-55-33-44-54-61/approval

You may think of it as "I'm removing the sub-resource "approval" and now this device doesn't have this association anymore. 您可能会将其视为“我正在删除子资源”批准“,现在此设备不再具有此关联。

Would the following PATCH call make sense? 以下PATCH调用是否有意义?

PATCH v1/devices/EF-55-33-44-54-61/approve PATCH v1 / devices / EF-55-33-44-54-61 / approve

REST is not RPC, so you should not bind your operations to URIs, you should bind them rather to method (verb) - URI (nouns) pairs. REST不是RPC,所以你不应该将你的操作绑定到URI,你应该将它们绑定到方法(动词) - URI(名词)对。 So in your case the /approve verb is not RESTish, and your request body is not RESTish too, because it contains a command rather than a resource representation. 所以在你的情况下, /approve动词不是RESTish,你的请求体也不是RESTish,因为它包含一个命令而不是资源表示。

I would use something like these instead: 我会用这样的东西代替:

  • PUT v1/devices/EF-55-33-44-54-61/state "approved"
  • PATCH v1/devices/EF-55-33-44-54-61 {state: "approved"}

Note that real REST clients follow hyperlinks instead of building for example the URI. 请注意,真正的REST客户端遵循超链接而不是构建URI。 That's (amongst many things) what makes them loosely coupled. 这是(在许多事情中)是什么使他们松散耦合。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM