带有向导的网页的REST API设计


11

我有一个向导格式的网页。API的提交按钮将位于向导的第4步。但是,我希望输入的数据先存储在数据库中,然后再进行向导的下一步。我还希望REST API适用于具有单个选项卡的页面。

因此,我设计了API以采用查询参数action =草稿或提交。如果采取行动,则仅某些字段是必填字段。如果提交了操作,则所有字段均为必填。REST API服务层中的验证将基于查询参数完成。看来我必须在文档中明确指定if / else子句。这是RESTful设计的可接受形式吗?满足这些要求的最佳设计是什么?


3
为什么需要将临时数据存储在数据库中?
Dan1701 2016年

2
@ Dan1701:因此您可以从另一台计算机上恢复向导。填写冗长而复杂的表格时,可能需要几天的时间才能完成所有必需的数据,因为用户可能手头没有准备好所有必需的数据,或者用户可能需要收集其他文件才能从其他位置上传。如果你可以从不同的设备恢复,可以加载该向导从上传手机照片,并继续在桌面上一个真正的键盘,打字等长描述/参数
李瑞安

在这种情况下,我认为@ guillaume31的答案很有意义。
Dan1701 2016年

Answers:


7

由于您希望在向导步骤之间将事物保留在服务器上,因此将每个步骤视为一个单独的资源似乎是完全可以接受的。遵循以下原则:

POST /wizard/123/step1
POST /wizard/123/step2
POST /wizard/123/step3

通过在响应中包括超媒体链接,您可以告知客户端此步骤后可以执行的操作-前进或后退以执行中间步骤,最后一步则什么也不做。你可以看到在图5中它的一个例子在这里


我在UI中使用Angular。所以我不确定状态机有多大帮助。但是我认为基于步骤的资源似乎比管理另一个表更有意义。另外,我应该能够一步一步提交所有内容。今天就来尝试一下这个设计。谢谢您的帮助。
TechCrunch

别客气。顺便说一下,“两表”方法并不与此互斥。每步只有一个HTTP资源并不能决定应用程序服务器上的对象模型,更不用说数据库模式了。这只是一个Web表示。
guillaume31

1
@TechCrunch基本上,Guillaume意味着可以将表示表单的对象/表分解为多个部分,并在每个步骤中保存模型的一部分。实际上,您可以使每个“步骤”成为整个模型一部分的形式。而且,如果采用这种方法,它实际上会使架构变得异常简单。到服务器的每个POST将(创建或更新)相同的模型,并且每个GET将加载相同的模型,并且每个步骤将是一种形式,用于填充语义上有意义的字段集(在一起)。并且只需在模型上为in_progress或设置布尔值即可draft
克里斯·西里菲斯

3

前段时间我需要做类似的事情,以下内容描述了最终的结果。

我们有两个表,Item和UnfinishedItem。当用户使用向导填写数据时,数据将存储在UnfinishedItem表中。在每个向导步骤中,服务器都会验证在该步骤中输入的数据。当用户完成向导后,向导将在确认页面中呈现隐藏/只读表单,该页面显示所有要提交的数据。用户可以查看此页面并返回到相关步骤以更正错误。一旦用户对他们的输入感到满意,用户将单击提交,然后向导会将隐藏/只读表单字段中的所有数据提交给API服务器。当API服务器处理此请求时,它将重新运行它在向导的每个步骤中所做的所有验证,并执行不适合各个步骤的其他验证(例如,全局验证,昂贵的验证)。

两表方法的优点:

  • 在数据库中,与未完成项目表相比,对项目表的约束可能更严格;您不必具有向导完成后实际上将需要的可选列。

  • 由于您不必记住将UnfinishedItems排除在外,因此汇总报表中的汇总查询更加容易。在我们的例子中,我们不需要在Item和UnfinishedItems之间进行聚合查询,因此这不是问题。

缺点:

  • 容易重复验证逻辑。由于我们使用模型继承和一些元魔术来更改需要在Item和UnfinishedItem中不同的约束,因此我们使用的Web框架Django使这一点更容易接受。Django会根据模型生成大多数数据库和表单验证,我们只需要在其上进行一些其他验证即可。

我考虑过的其他可能性以及为什么我们不选择它们:

  • 将数据保存在Cookie或本地存储中:用户无法继续从其他设备提交数据或删除浏览器历史记录
  • 将UnfinishedItem作为非结构化数据(例如JSON)存储在数据库或辅助数据存储上:我将必须定义解析逻辑,并且不能使用Django的自动模型/表单验证。
  • 在客户端执行每步验证:我将不得不在Python / Django和JavaScript之间复制验证逻辑。

1
+1用于指出对“草稿”型模型和“成品”模型的验证;我没有想到这一点,这是应该考虑的重要点。否则,您可能会if在整个验证过程中使用一堆语句检查草稿状态,这是不好的。如果正确实施,某些非常复杂的框架(如Ruby on Rails)可以大大简化该问题。
克里斯·西里菲斯

1

我以类似于@ guillauma31和@Lie Ryan的解决方案的混合方式实现了这一点。

以下是关键概念:

  1. 有一个三步向导,可能会部分保留直到完成。
  2. 每一步都有它自己的资源(如:/users/:id_user/profile/step_1.../step_2等)
  3. 在每个步骤中,可以通过GET请求检索数据和完成状态,并通过PATCH请求将其保留。
  4. 每个资源对输入的数据都有自己的验证规则。
  5. 每个步骤都返回一个密钥,该密钥必须在下一步的输入中使用以保证顺序。一旦使用或生成新令牌,此令牌将过期。
  6. 在最后一步,我们将所有需要的数据存储在数据库中,并显示确认屏幕。该确认调用另一个资源以将数据标记为已完成(例如:).../profile/confirm。该资源不需要再次接收所有数据。它仅将数据标记为正确和完整。
  7. 有一个计划的例程可以擦除几天以上的不完整条目。

前端人员必须照顾令牌,以使向导来回工作。

该API是无状态且原子的。

要使“一步向导”与此设置配合使用,您必须进行一些更改,例如删除令牌流或创建基于向导类型返回令牌的资源,甚至创建新资源仅用于填充此特定单步骤向导(如PUT /users/:id_user/profile/)。

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.