为需要为每个请求保存数据的 REST API 建模端点

Modelling a endpoint for a REST API that need save data for every request

不久前我参加了一次采访,其中有一个关于 REST 建模的问题,以及如何以最佳方式实现它。问题是:

You have an REST API where you expose a method to consult the distance between two point, although you must save each request to this method to expose the request history.

有人问我在这种情况下应该使用哪种 HTTP 方法,对我来说,当时的逻辑答案是 GET 方法(执行这两个操作)。之后面试官问我为什么,因为我们也存储了请求,这个端点不再幂等了,之后我无法回复它。由于这仍然在我的脑海中,所以我决定在这里验证并看看其他人对这种情况应该使用哪种方法的意见(或者有多少,例如GET和POST)。

You have an REST API where you expose a method to consult the distance between two point, although you must save each request to this method to expose the request history.

您将如何在网络上执行此操作?您可能有一个带有表单的网页,并且该表单将具有用于收集起点和终点的输入控件。当您提交表单时,浏览器将使用控件中的数据以及表单元数据和标准 HTML 处理规则来创建将发送到服务器的请求。

从技术上讲,您可以使用 POST 作为表单的方法。这样做是完全合法的。但是,由于请求的语义是“有效只读”,更好的选择是使用 GET。

更准确地说,这意味着拥有一系列相似的资源,其表示形式包括有关查询字符串中描述的两个点的信息。

类似资源系列可能会作为单个 operation/route 在您的原始服务器上 实现 ,解析器从查询字符串中提取两个点并传递它们连同函数一起作为参数。

the interviewer asked me why, because since we are also storing the request, this endpoint is not idempotent anymore

这可能是错误的异议 - GET 请求的语义是安全(有效只读)。所以面试可能会争辩说保存请求历史不是只读的。但是,这种反对是无效的,因为语义约束适用于请求消息,而不是实现。

例如,您可能已经注意到 HTTP 服务器通常会为每个请求在其访问日志中添加一个条目。显然,这不是“只读”——但它只是一个实现细节;客户的要求并没有说“还要记录这个”。

GET 在这里仍然可以,即使服务器正在记录内容。

一个可能的反对意见是,如果我们使用 GET,那么有时缓存会 return 先前的响应,而不是将请求一直传递到原始服务器以进行记录。这很棒 - 缓存是 Web 可以达到 Web 规模的重要原因。

但如果您不想缓存,正确的处理方法是将元数据添加到响应中以禁止缓存,而不是更改 HTTP 方法。


另一种可能性,更符合面试官的“幂等”言论,他们希望这个“请求历史”成为客户可以编辑的资源,而查找距离将是编辑过程。

例如,我们可能有某种“行程”资源,其中有一条或多条路线由客户提供。每次客户端修改行程(例如,添加另一条行程)时,都会自动调用距离查找方法。

在这种问题中,客户端正在(逻辑上)编辑资源,请求不再是“有效只读”。所以 GET 不在 table 作为选项,我们必须研究其他可能性。

TL;DR 版本是 POST 将始终接受 table(这就是我们在网络上的做法),但您可能更喜欢 API客户端在本地编辑资源表示的样式,在这种情况下,您可以让客户端在 PUT 和 PATCH 之间进行选择。