如何实现 RESTful API 以更改大型集合条目的顺序?

Hak*_*aba 5 api rest http json-patch

我有一个可能包含大量资源的端点。它们以分页列表的形式返回。每个资源都有一个唯一的id、一个rank字段和一些其他数据。从语义上讲,资源是根据其 进行排序的rank。用户应该能够更改该顺序。我正在寻找一个 RESTful 接口来更改rank大型集合中许多资源中的字段。

对一项资源重新排序可能会导致许多资源的字段发生更改rank。例如,考虑将最不重要的资源移动到最重要的位置。许多资源可能需要“降低其级别”。

分页的集合使问题变得更加困难。之前也有过类似的问题,关于一个小集合

rank字段是整数类型。如果它能产生合理的接口,我可以更改它的类型。


例如:

GET /my-resources?limit=3&marker=234返回:

{
  "pagination": {
    "prevMarker": 123,
    "nextMarker": 345
  },
  "data": [
    {
      "id": 12,
      "rank": 2,
      "otherData": {}
    },
    {
      "id": 35,
      "rank": 0,
      "otherData": {}
    },
    {
      "id": 67,
      "rank": 1,
      "otherData": {}
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

经过深思熟虑的方法。

1) 对列表的 PATCH 请求。

我们可以使用标准 json-patch 请求修改排名字段。例如以下内容:

[
  {
    "op": "replace",
    "path": "/data/0/rank",
    "value": 0
  },
  {
    "op": "replace",
    "path": "/data/1/rank",
    "value": 1
  },
  {
    "op": "replace",
    "path": "/data/2/rank",
    "value": 2
  }
]
Run Code Online (Sandbox Code Playgroud)

我发现这种方法存在的问题:

a) 在补丁操作中使用数组索引path。每个资源都已经有一个唯一的 ID。我宁愿用那个。

b) 我不确定分页集合中的数组索引应该引用什么?我想一旦所有页面都被接收并背靠背合并,它应该引用全局索引。

c) 集合中资源的索引可能会被其他客户端更改。当前客户对索引 1 的看法可能不再是该索引。我想可以先在补丁请求中添加测试操作。因此完整的补丁请求将如下所示:

[
  {
    "op": "test",
    "path": "/data/0/id",
    "value": 12
  },
  {
    "op": "test",
    "path": "/data/1/id",
    "value": 35
  },
  {
    "op": "test",
    "path": "/data/2/id",
    "value": 67
  },
  {
    "op": "replace",
    "path": "/data/0/rank",
    "value": 0
  },
  {
    "op": "replace",
    "path": "/data/1/rank",
    "value": 1
  },
  {
    "op": "replace",
    "path": "/data/2/rank",
    "value": 2
  }
]
Run Code Online (Sandbox Code Playgroud)

2)使集合成为“字典”/json对象并使用字典的补丁请求。

与 1) 相比,此方法的优点是我们可以在path修补操作中使用唯一 ID。返回资源中的“数据”将不再是列表:

{
  "pagination": {
    "prevMarker": 123,
    "nextMarker": 345
  },
  "data": {
    "12": {
      "id": 12,
      "rank": 2,
      "otherData": {}
    },
    "35": {
      "id": 35,
      "rank": 0,
      "otherData": {}
    },
    "67": {
      "id": 67,
      "rank": 1,
      "otherData": {}
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后我就可以在补丁操作中使用唯一的 ID。例如:

{
    "op": "replace",
    "path": "/data/12/rank",
    "value": 0
  }
Run Code Online (Sandbox Code Playgroud)

我发现这种方法存在的问题:

a) my-resources 集合可能很大,我对分页 json 对象或分页字典的含义有困难。我不确定是否可以在这个大对象上定义迭代顺序。

3) 有一个单独的端点用于使用 PUT 修改排名

我们可以添加一个像这样的新端点PUT /my-resource-ranks。并期望在 PUT 请求中传递有序 id 的完整列表。例如

[
  {
    "id": 12
  },
  {
    "id": 35
  },
  {
    "id": 67
  }
]
Run Code Online (Sandbox Code Playgroud)

我们将把该MyResource.rank字段设置为只读字段,以便它无法通过其他端点进行修改。

我发现这种方法存在的问题:

a) 需要发送完整的有序列表。在 PUT 请求中,/my-resource-ranks我们不会包含任何其他数据,而仅包含资源的唯一 ID。它没有发送完整资源那么严重,但完整的有序列表仍然可能很大。

4) 避免使用该MyResource.rank字段,并且“排名”是 /my-collections 响应中的顺序。

返回的资源中不会有“排名”字段,并且它们已经根据响应中的排名进行排序。

{
  "pagination": {
    "prevMarker": 123,
    "nextMarker": 345
  },
  "data": [
    {
      "id": 35,
      "otherData": {}
    },
    {
      "id": 67,
      "otherData": {}
    },
    {
      "id": 12,
      "otherData": {}
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

用户可以通过 json-patch 中的移动操作更改顺序。

[
  {
    "op": "test",
    "path": "/data/2/id",
    "value": 12
  },
  {
    "op": "move",
    "from": "/data/2",
    "path": "/data/0"
  }
]
Run Code Online (Sandbox Code Playgroud)

我发现这种方法存在的问题:

/my-collectionsa)从客户端的角度来看,我希望服务器可以自由地以“任意”顺序返回。只要顺序一致,“更简单”服务器实现的最佳顺序可能与应用程序定义的排名不同。

b) 与 1)b) 相同的问题。一旦所有页面都被接收并背靠背合并,修补操作中的索引是否引用全局索引?或者它引用当前页面中的索引?


更新:

有谁知道现有公共 API 的更多示例吗?寻找进一步的灵感。到目前为止我有:

Eve*_*ert 0

我会

  • 使用补丁
  • 定义专门用于更新订单的专用内容类型。

application/patch+json 类型非常适合进行直接修改,但我认为您的用例足够独特,足以保证有用的、最小的专门内容类型。