您如何最好地在REST API中表示双向同步?


23

假设系统中有一个带资源的Web应用程序,以及另一个具有类似资源的远程应用程序的引用,那么您如何表示双向同步操作,该操作将“本地”资源与“远程”资源同步?

例:

我有一个代表待办事项清单的API。

GET / POST / PUT / DELETE / todos /等

该API可以引用远程TODO服务。

GET / POST / PUT / DELETE / todo_services /等

我可以通过我的API作为代理通过远程服务来处理待办事项

GET / POST / PUT / DELETE / todo_services / abc123 /等

我希望能够在本地待办事项集和远程待办事项集之间进行双向同步。

以一种rpc的方式,

POST / todo_services / abc123 / sync /

但是,在“动词很糟糕”的想法中,是否有更好的方法来表示此动作?


4
我认为,一个好的API设计绝对取决于对同步含义的非常具体的理解两个数据源的“同步”通常是一个非常复杂的问题,非常容易简化,但在所有含义上都很难考虑。使其成为“双向”同步,难度突然变得更高。从思考即将出现的非常困难的问题开始。
亚当·克罗斯兰

正确-假设同步算法是在“代码级” API中设计并起作用的-我如何通过REST公开它。同步的一种方式似乎更容易表达:我GET /todo/1/POST它之间的联系很容易。/todo_services/abc123/ 但是,第二种方式-我没有获取数据集并将其放入资源中,而我正在采取的行动实际上导致了对两种资源的潜在修改。我想我可能会依赖“待办事项同步化”本身作为资源 POST /todo_synchronizations/ {"todos":["/todo/1/","/todo_services/abc123/1"],"schedule":"now"}
Edward M Smith

我们还有马车问题。我的观点是,您不能假设同步仅能正常工作并设计API。API的设计将受到对同步算法确切工作方式的众多关注的驱动。
亚当·克罗斯兰

这可能会暴露出有用的结果: GET /todo_synchronizations/1=>{"todos":["/todo/1/","/todo_services/abc123/1"],"schedule":"now","ran_at":"datetime","result":"success"}
爱德华·M·史密斯

2
我同意@Adam。您知道如何实现同步吗?您如何处理变更?您是否只是想调整两组项目,或者是否有导致自上次同步以来两组发生差异的操作日志?我问的原因是检测添加和删除(与REST无关)可能很棘手。如果您有一个对象服务器端,而没有客户端,则必须问自己:“客户端删除了它还是服务器创建了它?” 只有准确地知道“资源”的行为方式,您才能在REST中准确地表示它。
雷蒙德·萨尔特雷利

Answers:


17

资源在哪里,有什么?

REST就是以无状态,可发现的方式寻址资源。尽管强烈建议使用超媒体数据格式(请参阅HATEOAS原理),但由于需要链接和ID ,因此不必通过HTTP来实现,也不必依赖JSON或XML 。

因此,问题就变成了:人们如何在资源方面考虑同步?

什么是双向同步?**

双向同步是更新存在于节点图上的资源的过程,以便在该过程结束时,所有节点都已根据管理这些资源的规则更新了其资源。通常,这应理解为所有节点都具有该图内显示的资源的最新版本。在最简单的情况下,该图由两个节点组成:本地和远程。本地启动同步。

因此,需要处理的关键资源是事务日志,因此,对于HTTP下的“项目”集合,同步过程可能看起来像这样:

步骤1-本地检索事务日志

本地: GET /remotehost/items/transactions?earliest=2000-01-01T12:34:56.789Z

远程: 200 OK,主体包含事务日志,该事务日志包含与此类似的字段。

  • itemId -提供共享主键的UUID

  • updatedAt -时间戳,用于提供上次更新数据的时间(假设不需要修订历史记录)

  • fingerprint-如果updateAt超出几秒钟,则将数据内容的SHA1哈希用于快速比较

  • itemURI -项目的完整URI,以便以后检索

第2步-本地将远程事务日志与其自己的日志进行比较

这是如何同步业务规则的应用程序。通常,itemId将识别本地资源,然后比较指纹。如果存在差异,则进行比较updatedAt。如果这些距离太近而无法调用,则需要基于其他节点(可能更重要)做出决定,或者推到其他节点(此节点更重要)。如果本地不存在远程资源,则进行推送条目(其中包含用于插入/更新的实际数据)。远程事务日志中不存在的任何本地资源都假定为不变。

对远程节点发出拉取请求,以便使用可以在本地存储数据itemURI。直到以后才在本地应用它们。

步骤3-将本地同步事务日志推送到远程

本地: PUT /remotehost/items/transactions主体包含本地同步事务日志。

如果远程节点可能会产生大量开销,则它可以同步(如果它又小又快)或异步(认为202 ACCEPTED)来处理。假设同步操作,则取决于成功或失败,结果将为200 OK409 CONFLICT。对于409 CONFLICT,则必须重新开始该过程,因为远程节点上存在乐观的锁定失败(有人在同步期间更改了数据)。远程更新在其自己的应用程序事务下进行处理。

第4步-本地更新

在步骤2中提取的数据在应用程序事务下本地应用。

尽管上述方法并不完美(在某些情况下,本地和远程可能会遇到麻烦,并且从本地进行远程提取数据可能比将其填充到大型PUT中更为有效),但它确实演示了如何在双向操作期间使用REST。定向同步过程。


6

我将同步操作视为可以访问(GET)或创建(POST)的资源。考虑到这一点,API URL可以是:

/todo_services/abc123/synchronization

(将其称为“同步”,而不是“同步”以使其清楚不是动词)

然后做:

POST /todo_services/abc123/synchronization

启动同步。由于同步操作是一种资源,因此此调用可能会返回一个ID,该ID可用于检查操作的状态:

GET /todo_services/abc123/synchronization?id=12345

3
这个简单的答案就是答案。将您的动词变成名词,然后继续...
HDave 2015年

5

这是一个难题。我认为REST不是实现同步的适当级别。健壮的同步本质上将需要是分布式事务。REST不是该工作的工具。

(假设:通过“同步”,您意味着任一资源都可以随时独立于另一资源进行更改,并且您希望能够重新调整它们而不会丢失更新。)

您可能需要考虑将一个作为“主”,将另一个作为“从”,这样您就可以自信地定期用来自主的数据破坏从服务器。

如果您绝对需要支持独立更改的数据存储,则可能还需要考虑使用Microsoft Sync Framework。这将无法通过REST进行,但会在后台进行。


5
+1为“难题”。双向同步是其中的一件事,直到您陷入泥潭,您才意识到它有多难。
丹·雷

2

Apache CouchDB是基于REST,HTTP和JSON的数据库。开发人员通过HTTP执行基本的CRUD操作。它还提供了仅使用HTTP方法的对等复制机制。

要提供此复制,CouchDB需要具有一些特定于CouchDB的约定。这些都不反对REST。它为每个文档(数据库中的REST资源)提供一个修订号。这是该文档的JSON表示的一部分,但也位于ETag HTTP标头中。每个数据库还具有一个序列号,该序列号允许跟踪整个数据库的更改

为了解决冲突,他们只是注意到文档有冲突并保留了冲突的版本,然后将其留给使用数据库的开发人员提供冲突解决算法。

您可以将CouchDB用作REST API,这将使您开箱即用地进行同步,或者看看它如何提供复制以提供制作自己的算法的起点。


我喜欢CouchDB,它是CouchBase + SyncGateway的继承者。+1
Leonid Usov

-1

您可以通过简单的重命名来解决“动词不好”的问题-使用“更新”而不是“同步”。

同步过程实际上是发送自上次同步以来所做的本地更新的列表,并同时接收服务器上所做的更新的列表。

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.