Как реализовать RESTful API для изменения порядка в записях больших коллекций?

У меня есть конечная точка, которая может содержать большое количество ресурсов. Они возвращаются в виде списка с разбивкой на страницы. Каждый ресурс имеет уникальное поле 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": {}
    }
  ]
}

Рассмотрены подходы.

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
  }
]

Проблемы, которые я вижу при таком подходе:

a) Использование индексов массива в path в операциях исправления. У каждого ресурса уже есть уникальный идентификатор. Я бы предпочел это использовать.

б) Я не уверен, на что должен ссылаться индекс массива в разбитой на страницы коллекции? Я предполагаю, что он должен ссылаться на глобальный индекс после того, как все страницы будут получены и объединены друг с другом.

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
  }
]

2) Сделайте коллекцию объектом «словарь» / json и используйте запрос патча для словаря.

Преимущество этого подхода перед 1) состоит в том, что мы можем использовать уникальные идентификаторы в path в операциях исправления. «Данные» в возвращаемых ресурсах больше не будут списком:

{
  "pagination": {
    "prevMarker": 123,
    "nextMarker": 345
  },
  "data": {
    "12": {
      "id": 12,
      "rank": 2,
      "otherData": {}
    },
    "35": {
      "id": 35,
      "rank": 0,
      "otherData": {}
    },
    "67": {
      "id": 67,
      "rank": 1,
      "otherData": {}
    }
  }
}

Тогда я мог бы использовать уникальный идентификатор в операциях исправления. Например:

{
    "op": "replace",
    "path": "/data/12/rank",
    "value": 0
  }

Проблемы, которые я вижу при таком подходе:

a) Коллекция my-resources может быть большой, мне сложно понять значение разбитого на страницы объекта json или разбитого на страницы словаря. Я не уверен, можно ли определить порядок итераций для этого большого объекта.

3) Имейте отдельную конечную точку для изменения рангов с помощью PUT

Мы могли бы добавить такую ​​новую конечную точку PUT /my-resource-ranks. И ожидайте, что полный список упорядоченных идентификаторов будет передан в запросе PUT. Например

[
  {
    "id": 12
  },
  {
    "id": 35
  },
  {
    "id": 67
  }
]

Мы бы сделали MyResource.rank поле только для чтения, чтобы его нельзя было изменить через другие конечные точки.

Проблемы, которые я вижу при таком подходе:

а) Необходимость отправки полного заказанного списка. В запрос PUT для /my-resource-ranks мы не будем включать никаких других данных, а только уникальные идентификаторы ресурсов. Это менее серьезно, чем отправка полных ресурсов, но все же полный упорядоченный список может быть большим.

4) Избегайте использования поля MyResource.rank и порядка в ответе / my-collections.

В возвращаемых ресурсах не будет поля «ранг», и они будут уже отсортированы по рангу в ответе.

{
  "pagination": {
    "prevMarker": 123,
    "nextMarker": 345
  },
  "data": [
    {
      "id": 35,
      "otherData": {}
    },
    {
      "id": 67,
      "otherData": {}
    },
    {
      "id": 12,
      "otherData": {}
    }
  ]
}

Пользователь мог изменить порядок с помощью операции move в json-patch.

[
  {
    "op": "test",
    "path": "/data/2/id",
    "value": 12
  },
  {
    "op": "move",
    "from": "/data/2",
    "path": "/data/0"
  }
]

Проблемы, которые я вижу при таком подходе:

а) Я бы предпочел, чтобы сервер мог возвращаться к /my-collections в «произвольном» порядке с точки зрения клиента. Пока порядок согласован, оптимальный порядок для «более простой» реализации сервера может отличаться от ранга, определенного приложением.

б) То же, что и 1) б). Обращается ли индекс в операции исправления к глобальному индексу после получения и объединения всех страниц подряд? Или это относится к индексу на текущей странице?


Обновлять:

Кто-нибудь знает дополнительные примеры из существующего общедоступного API? Ищу дальнейшее вдохновение. Пока у меня есть:


person Hakan Baba    schedule 31.01.2019    source источник


Ответы (1)


я мог бы

  • Использовать ПАТЧ
  • Определите специализированный тип контента специально для обновления заказа.

Тип application / patch + json довольно хорош для внесения прямых изменений, но я думаю, что ваш вариант использования достаточно уникален, чтобы гарантировать полезный минимальный специализированный тип контента.

person Evert    schedule 31.01.2019