我正在为客户管理系统编写一个RESTful服务,并试图找到部分更新记录的最佳实践。例如,我希望调用者能够使用GET请求读取完整的记录。但是为了更新它,只允许对记录进行某些操作,比如将状态从ENABLED更改为DISABLED。(我有比这更复杂的场景)
出于安全原因,我不希望调用者只提交更新字段的整个记录(这也感觉有点过分)。
是否有构造uri的推荐方法?在阅读REST书籍时,RPC样式的调用似乎是不受欢迎的。
如果下面的调用返回id为123的客户的完整客户记录
GET /customer/123
<customer>
{lots of attributes}
<status>ENABLED</status>
{even more attributes}
</customer>
我该如何更新状态?
POST /customer/123/status
<status>DISABLED</status>
POST /customer/123/changeStatus
DISABLED
...
更新:扩充问题。如何将“业务逻辑调用”合并到REST api中?有没有大家都同意的做法?并非所有的方法本质上都是CRUD。有些更复杂,如“sendEmailToCustomer(123)”,“mergeCustomers(123, 456)”,“countCustomers()”
POST /customer/123?cmd=sendEmail
POST /cmd/sendEmail?customerId=123
GET /customer/count
RFC 7396: JSON Merge Patch(在这个问题发布四年后发布)从格式和处理规则方面描述了Patch的最佳实践。
简而言之,您向目标资源提交一个HTTP PATCH,它带有application/merge-patch+json MIME媒体类型和一个只表示您想要更改/添加/删除的部分的主体,然后遵循以下处理规则。
规则:
如果提供的合并补丁包含未出现在目标中的成员,则会添加这些成员。
如果目标不包含该成员,则替换该值。
合并补丁中的空值被赋予特殊含义,以指示删除目标中的现有值。
演示上述规则的示例测试用例(见RFC的附录):
ORIGINAL PATCH RESULT
--------------------------------------------
{"a":"b"} {"a":"c"} {"a":"c"}
{"a":"b"} {"b":"c"} {"a":"b",
"b":"c"}
{"a":"b"} {"a":null} {}
{"a":"b", {"a":null} {"b":"c"}
"b":"c"}
{"a":["b"]} {"a":"c"} {"a":"c"}
{"a":"c"} {"a":["b"]} {"a":["b"]}
{"a": { {"a": { {"a": {
"b": "c"} "b": "d", "b": "d"
} "c": null} }
} }
{"a": [ {"a": [1]} {"a": [1]}
{"b":"c"}
]
}
["a","b"] ["c","d"] ["c","d"]
{"a":"b"} ["c"] ["c"]
{"a":"foo"} null null
{"a":"foo"} "bar" "bar"
{"e":null} {"a":1} {"e":null,
"a":1}
[1,2] {"a":"b", {"a":"b"}
"c":null}
{} {"a": {"a":
{"bb": {"bb":
{"ccc": {}}}
null}}}
你的扩充问题需要补充的东西。我认为您通常可以完美地设计更复杂的业务操作。但你必须放弃方法/过程的思维方式,更多地考虑资源和动词。
邮件发送
POST /customers/123/mails
payload:
{from: x@x.com, subject: "foo", to: y@y.com}
这个资源+ POST的实现将发送邮件。如果有必要,你可以提供类似/customer/123/发件箱这样的东西,然后提供到/customer/mails/{mailId}的资源链接。
客户数
您可以像处理搜索资源一样处理它(包括具有分页和num-found信息的搜索元数据,它可以提供客户的数量)。
GET /customers
response payload:
{numFound: 1234, paging: {self:..., next:..., previous:...} customer: { ...} ....}