用于验证答案的 rest API 中的正确路径是什么?

问题描述

出于教育目的,我正在 MERN 堆栈中构建一个网站。它有一个调查问卷,其中包含针对一个特定主题的 40 个“是或否”问题(可以是对也可以是错的陈述)。可以有很多主题,但所有主题的陈述总是相同的。

用户完成回答后,答案应该被发布到(或从?)一个休息 API。

后端只是从数据库获取正确的答案,然后根据这些答案验证用户的答案并给出结果。

后端的模型只是简单的文档,每个文档都包含 subject id 和 40 个布尔值 as1as40

(nosql 新手,所以我可能已经完全删除了我的模型,在这种情况下,我很乐意接受纠正!)

调用此休息服务的正确方法是什么?

我想我要使用这样的 POST 正文:

{
    "answers": {
        "uas1": true,"uas2": false,...
        "uas39": true,"uas40": false
    }
}

...但是路径应该是什么样的?

/statements/:id/answer

解决方法

调用此休息服务的正确方法是什么?

您需要解决的主要问题是了解客户端是获取资源(有效的只读操作)还是修改资源。获取资源可能意味着从缓存中获取资源,而不是让请求一直传递到您的服务器。

后端只是从数据库中获取正确的答案,然后根据这些答案验证用户的答案并给出结果。

这听起来很像有效只读的情况:给定答案列表,找到匹配的答案文档。因此,对于这种资源模型,通常的答案是使用 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 请求将导致通用缓存invalidate 以前使用相同的有效 uri 存储的响应。

通用组件甚至不能假设 POST 请求具有幂等语义,因此如果响应丢失,HTTP 应用程序无法通过重新发送请求来自动帮助我们。


如果有效的只读语义不是您想要的,那么 it is okay to use 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。

,

您应该设计 API 端点(或“路径”),使它们真正具有描述性,并且针对每个场景。所以考虑到这一点,其中一个端点可能看起来像:

/subject/:subject_id/answers

然后在您的前端,您将 POST 请求发送到例如

http://127.0.0.1/3000/subject/23/answers

请求正文如下所示:

{
    "answers": {
        "uas1": true,"uas40": false
    }
}

这个端点本质上的作用是将 ID 为 23 的主题的所有 40 个布尔答案发送到您的 Express.js 服务器。

然后您的服务器将解析请求并从您的 req.body 中获取答案,然后根据您的 MongoDB 数据库进行检查。该检查的结果然后可以在如下响应中发回:

res.status(200).send(`For subject ${subject_name},you scored ${correct_answers}/40`) 

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...