REST端点在发布前显示预览


17

我正在设计一个新的Web应用程序,该应用程序由REST后端和HTML + JS前端提供支持。

它具有一个POST方法来更改一个实体(我们称为Config),这在应用程序的许多元素的状态下具有多种副作用。假设以这种方式执行POST

POST /api/config BODY {config: ....}

因此,我想在进行这些更改之前显示预览,以使最终用户能够注意到要更改的内容。

我首先想到的是为预览创建一个GET端点,发送实体新状态的主体。这条路:

GET /api/preview/items BODY {config: ....}

可能显示具有新配置的项目的新状态。

GET /api/preview/sales BODY {config: ....}

可能会使用新配置显示销售的新状态。

使用GET动词似乎是个好主意,因为我不会更改应用程序的状态。然而,随着使用请求主体的GET请求似乎气馁

有什么好的做法吗?其他选择可能是使用一种方法将配置存储为草稿,并使用其他方法显示结果,但这将需要额外的步骤,并且必须在服务器中管理草稿:

POST /api/preview/config BODY {config: ....}

GET /api/preview/items?idPreviewConfig=1

这个配置到底是什么?它对itemsor的影响如何sales?它会影响返回实体的表示吗?
安迪

假设项目和销售都受到您在配置中所做的更改的影响。
Xtreme Biker恢复Monica的时间为

但是这些变化意味着什么?它会更改返回的实体集吗?它会改变返回的结构吗?
安迪

其实它改变的价值观itemssales(未结构),根据不同的配置,你POST。
Xtreme Biker恢复Monica的时间为

配置到底有多大?能否增长到几百千字节甚至更多?
安迪

Answers:


27

这是特定于域的,因此无法在HTTP中提供本机支持。

而是,您可以执行以下任一操作:

  1. 有一个POST /api/config/preview。在服务器端,应用程序将知道它不应该修改实际配置,而是将实际配置与您发布的配置进行组合,然后返回指示已更改的结果。

    稍后,如果用户对结果感到满意,她将执行一个POST /api/config包含与上一个请求相同的有效负载的。这将有效覆盖配置。

    这种方法的好处是您不会对当前的API进行任何重大更改。不需要预览功能的客户端仍然可以像以前一样更新条目。

    缺点是,当主体很大时,这意味着需要将其两次发送到服务器。如果是这种情况,则可以使用下一种方法。

  2. 有一个POST /api/config/prepare可以记住临时记录中发送的内容,并返回两件事:临时记录的ID(例如12345)和更改的预览。

    如果用户对结果满意,她将执行a POST /api/config/commit/12345以确定存储更改。如果不是,则临时记录可以保留一段时间,然后由cron作业丢弃。

    这样做的好处是,您可以再次保持原始状态POST /api/config不变,不需要预览的客户端也不会中断。

    缺点是(1)处理临时记录的操作可能很棘手(是什么让您认为一个小时就足够了?如果十分钟后内存不足,该怎么办?客户端在提交以下内容时如何处理HTTP 404: (2)提交记录的两步操作可能比需要的更为复杂。

  3. 在客户端上移动预览逻辑。


发送标题为“不要坚持下去,只告诉我该怎么办”的标题该怎么办?如果您满意,我会将其编辑为答案@ArseniMourzenko
marstato

1
@marstato:就我个人而言,我并不特别喜欢这种用法的HTTP标头。尽管这对其他人可能很有意义,但是如果您编辑我的答案,我也很好。请注意,您还可以发布自己的答案,这将允许其他人对其进行投票(并获得声誉得分)。
Arseni Mourzenko '17

我想选项1更适合我的情况。因此,您发布了预览配置,并且结果有所更改,而不必为每个定义的实体定义预览端点。似乎合理。从技术上来讲,唯一的事情是您正在使用POST对服务器进行任何更改。在我看来,选项3不可行。
Xtreme Biker恢复Monica的时间为2007年

1
@PedroWerneck您可以对此进行扩展吗?在我看来,选项2定义了另一个实体(配置草案),并提供了与它们交互的无状态方式。
安德鲁说莫妮卡(Reonica Monica)

1
@PedroWerneck它是有状态的,就像在服务器上存储配置是有状态的一样。因此,从您的角度来看,该应用程序已经是有状态的,添加该功能的所有选项也是如此。
jpmc26

10

在REST中对不同的api调用使用特定的HTTP动词的目的是利用现有的HTTP机制和期望。

在这种情况下,使用GET似乎对这两者都不利。

答:客户需要包括带有GET的主体吗?意外

B.服务器根据主体返回不同的get响应?破坏规范和缓存机制

如果您在面对RESTful问题,我的规则是问自己。

“这比仅对所有内容使用POST更好吗?”

除非有直接的明显好处,否则请使用Just Use POST Stupid(JUPS)策略



@Ewan ...不管这是否是一种实用的方法...如果您对所有内容都使用POST,则应注意它实际上不是RESTful的。
阿伦夫'17

1
好吧,除非POST是所有方法的适当选择。并不是说您可以应用一个客观的规则,我们只是在争论对准则的主观解释。
伊万(Ewan)

6

您可以发送一个标头,指示服务器“不要坚持下去,只告诉我如果这样做会带来什么结果”。例如

POST /api/config HTTP/1.1
Host: api.mysite.com
Content-Type: application/json
Persistence-Options: simulate

{
   "config": {
      "key": "value"
   }
}

服务器可以响应的:

HTTP/1.1 200 OK
Persistence-Options: simulated
Content-Type: application/json

-- preview --

请注意,如果您在数据库中使用基于工作单元的O / RM和/或每个请求的事务,则可以轻松地为所有端点实现此功能,而无需在任何特定端点上进行工作:如果请求带有该选项,请回滚事务/工作单元,而不要提交它。



@PeterRader好点,删除了X-
marstato

别客气。您是否说处于仿真状态的实体应表示为“处于仿真状态”?
彼得·拉德

没有; 多数民众赞成在模拟的重点,不是吗?标头值也可以是,none但就我的口味而言,它与POST方法的本质过于矛盾。
marstato

2

我建议您像对待搜索一样对待它。我将设置一个POST端点,在/api/config/preview该端点创建一个新的预览。然后,我将api/config根据您打算编辑当前配置还是简单地替换整个配置来设置一个PUT或PATCH端点(大概在前一种情况下,您将发送刚创建的预览)。


0

除了其他好的答案之外,另一个选择是发布所提到的配置,并且也可以使用回滚过程。我认为,与敏捷方法一样,最好通过拥有更精细,可重复和经过测试的过程来减少更改的恐惧感,这将在需要时为您提供备份,从而将风险降低到零或什至没有,这取决于应用程序。

再说一次,如果您可能有影响整个系统的配置错误,那么您想更积极地处理它,如果是这样,为什么不从服务器或客户机的角度着手在那一点上预览更改。虽然,我可以看到该预览功能的开发成本可能会更高,但是在用例中,有各自不同的步骤需要遵循和测试。


0

RFC6648不赞成使用新的X-构造,因此我必须反对发送新的标头字段的想法。REST是一种体系结构样式,我们谈论的是RESTful-但是暂时不要理会。

因为REST是代表性的(并且模拟在现实中没有表示)和状态的(并且在提交状态之前模拟是不处于状态),所以我们必须拥有一个新的范围,例如模拟范围。但是我们必须称其为仿真而不是仿真,因为仿真包括仿真过程,但是有状态的表示我们拥有一种站立状态,这是仿真的理想解决方案:仿真。因此,我们需要在URL中将其称为仿真。这可能也是一个很好的解决方案:

GET  /api/emulation - 200 OK {first:1, last:123}
POST /api/emulation/124 - 200 OK
GET  /api/emulation/124/config - 200 OK {config:{tax:8}}
PUT  /api/emulation/124/config {config:{tax:16}} - 200 OK {config:{tax:16}}
GET  /api/emulation/124/items - 200 OK [first:1, last: 3000]
GET  /api/emulation/124/items/1 - 200 OK {price:1.79, name:'Cup'}
--- show emulation ---
--- commit emulation ---
PUT /api/config {config:{tax:16}}
DELETE /api/emulation/124 - 200 OK

还有另一种方法....您可能会注意到,来自HTML / JavaScript客户端的许多请求可能会产生太多请求,同时达到约17个请求的限制(请参阅此页面)。您可以交换REST的用法,而不是传递la脚的对象状态,而可以传递丰富的用户特定页面状态。例:

GET /user/123/config - 200 OK {user:'Tim', date:3298347239847, currentItem:123, 
                  roles:['Admin','Customer'], config:{tax:16}, unsavedChanges:true, ...}

亲切的问候

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.