调用此休息服务的正确方法是什么?
您需要解决的主要问题是了解客户端是在获取资源(有效的只读操作)还是在修改资源。获取资源可能意味着将资源从缓存中取出,而不是让请求一直到达您的服务器。
后端只是从数据库中获取正确的答案,然后根据这些验证用户的答案并以结果进行响应。
这听起来很像有效的只读案例:给定答案列表,找到匹配的答案文档。因此,这种资源模型的通常答案是使用 GET。
在网络上,这可能看起来像一个带有 40 个不同问题的输入控件的大表单。用户会做出他们的选择,然后点击提交按钮。浏览器将使用输入来计算查询字符串,并执行 HTTP GET 请求,并将所有用户输入编码到查询部分(根据表单本身的元数据。
?a1=Y&a2=N&a3=T...&a40=Y
使用 HTML 表单,我们可以为我们想要的路径使用任何拼写,同样,对于查询部分中的键,我们可以使用任何我们想要的拼写,因为该信息成为表单元数据的一部分:浏览器可以只查看表单定义,并描述了如何创建有效的请求 URI(它是 HTML 表单处理标准的一部分)。
对于诸如主题 ID 之类的内容,您可以选择将该信息编码到路径中(通过使该信息成为表单操作的一部分)或查询部分(作为表单输入 - 可能“隐藏”)。
路径应该是什么样子?
你喜欢的任何东西 - REST 不关心你为资源标识符使用的拼写约定。
GET /83eeecdd-a680-475f-913b-07aa0239cec0?a1=Y&a2=N&a3=T...&a40=Y
……很好。不过,您可能想要对人类更好的东西——阅读日志的操作员、扫描浏览器历史记录的用户、试图为其他开发人员记录资源模型的作者等等。
GET /subject/:subject_id/answers?a1=Y&a2=N&a3=T...&a40=Y
也很好。
我想我要使用这样的 POST 正文:
根据您的描述,不是我的首选。
像这样的请求
POST /statements/:id/answer
Content-Type: application/json
{...}
从通用组件的角度来看,约束很少;通用组件不能假定 POST 是有效只读的。这意味着我们无法从缓存中提取答案。事实上,情况正好相反:一个成功的 POST 请求将导致通用缓存使用相同的有效 uri 使以前存储的响应无效。
通用组件甚至不能假设 POST 请求具有幂等语义,因此如果响应丢失,HTTP 应用程序无法通过重新发送请求来自动帮助我们。
如果您不需要有效的只读语义,则可以使用 POST。对于 HTML 表单,这将是我们唯一真正的选择。
但是,如果您可以设计您的资源模型,使得每组提交的答案都是它自己的资源,那就更好了。你可能会这样想:用户得到一份独特的问卷,其中所有的答案都是空白的。他们填写自己的答案,并返回该独特问卷的新表示。
将您的 API 实现为对文档的编辑允许您使用 PUT;PUT 具有幂等语义,这意味着当响应在不可靠的网络上丢失时,通用组件可以自动提供帮助。
PUT /statements/123/answers/Bob
Content-Type: application/json
{
"answers": {
"uas1": true,
"uas2": false,
...
"uas39": true,
"uas40": false
}
}
在这里,我们有一个特定于 Bob 答案的资源,并且请求描述了对该资源的编辑。
从技术上讲,您可以让每个人都编辑相同的资源
PUT /statements/123/answers
...
这不是很好,但你会得到很多好处。每个成功提交的请求都会使目标资源失效,但您可能不太在意。
我不会将此方法称为 REST 兼容的,但它可能算作 REST-close-enough-that-you-get-away-with-it。