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