Подтвердить что ты не робот

Полезная нагрузка для постраничного ответа из API RESTful

Я хочу поддерживать разбивку на страницы в моем RESTful API.

Мой API-метод должен вернуть список продуктов JSON через /products/index. Тем не менее, есть потенциально тысячи продуктов, и я хочу их просматривать, поэтому моя просьба должна выглядеть примерно так:

/products/index?page_number=5&page_size=20

Но каков должен быть мой ответ JSON? Потребители API обычно ожидают метаданные разбиения на страницы в ответе? Или нужен только набор продуктов? Почему?

Похоже, что API Twitter включает метаданные: https://dev.twitter.com/docs/api/1/get/lists/members (см. Пример запроса).

С метаданными:

{
  "page_number": 5,
  "page_size": 20,
  "total_record_count": 521,
  "records": [
    {
      "id": 1,
      "name": "Widget #1"
    },
    {
      "id": 2,
      "name": "Widget #2"
    },
    {
      "id": 3,
      "name": "Widget #3"
    }
  ]
}

Просто массив продуктов (без метаданных):

[
  {
    "id": 1,
    "name": "Widget #1"
  },
  {
    "id": 2,
    "name": "Widget #2"
  },
  {
    "id": 3,
    "name": "Widget #3"
  }
]
4b9b3361

Ответ 1

API ReSTful потребляются в основном другими системами, поэтому я помещаю данные подкачки в заголовки ответов. Тем не менее, некоторые пользователи API могут не иметь прямого доступа к заголовкам ответов или могут создавать UX по вашему API, поэтому предоставление способа получения (по запросу) метаданных в ответе JSON является плюсом.

Я полагаю, что ваша реализация должна включать машиночитаемые метаданные в качестве значения по умолчанию и метаданные, доступные для чтения по запросу. Человекочитаемые метаданные могут быть возвращены с каждым запросом, если вам нравится или, желательно, по запросу через параметр запроса, например include=metadata или include_metadata=true.

В вашем конкретном сценарии я бы включил URI для каждого продукта с записью. Это позволяет потребителю API создавать ссылки на отдельные продукты. Я также задал бы некоторые разумные ожидания в соответствии с лимитами моих запросов подкачки. Принятие и документирование настроек по умолчанию для размера страницы является приемлемой практикой. Например, GitHub API устанавливает размер страницы по умолчанию в 30 записей с максимум 100, плюс устанавливает ограничение скорости на количество раз, когда вы можете запросить API. Если ваш API имеет размер страницы по умолчанию, строка запроса может просто указывать индекс страницы.

В сценарии, понятном человеку, при переходе на /products?page=5&per_page=20&include=metadata ответ может быть:

{
  "_metadata": 
  {
      "page": 5,
      "per_page": 20,
      "page_count": 20,
      "total_count": 521,
      "Links": [
        {"self": "/products?page=5&per_page=20"},
        {"first": "/products?page=0&per_page=20"},
        {"previous": "/products?page=4&per_page=20"},
        {"next": "/products?page=6&per_page=20"},
        {"last": "/products?page=26&per_page=20"},
      ]
  },
  "records": [
    {
      "id": 1,
      "name": "Widget #1",
      "uri": "/products/1"
    },
    {
      "id": 2,
      "name": "Widget #2",
      "uri": "/products/2"
    },
    {
      "id": 3,
      "name": "Widget #3",
      "uri": "/products/3"
    }
  ]
}

Для машиночитаемых метаданных я бы добавил заголовки ссылок в ответ:

Link: </products?page=5&perPage=20>;rel=self,</products?page=0&perPage=20>;rel=first,</products?page=4&perPage=20>;rel=previous,</products?page=6&perPage=20>;rel=next,</products?page=26&perPage=20>;rel=last

(значение заголовка ссылки должно быть уркокодировано)

... и, возможно, пользовательский заголовок ответа total-count, если вы так решите:

total-count: 521

Другие данные подкачки, обнаруженные в метаданных, ориентированных на человека, могут быть излишними для машинных метаданных, поскольку заголовки ссылок позволяют мне знать, на какой странице я нахожусь, и число на страницу, и я могу быстро получить количество записей в массиве. Поэтому я бы, вероятно, создал только заголовок для общего счета. Вы всегда можете изменить свое мнение и добавить больше метаданных.

В стороне, вы можете заметить, что я удалил /index из вашего URI. Общепринятое соглашение заключается в том, чтобы ваша конечная точка ReST выставляла коллекции. Имея /index в конце муфты, немного вверх.

Это всего лишь несколько вещей, которые мне нравятся при использовании/создании API. Надеюсь, что это поможет!

Ответ 2

Как кто-то, кто написал несколько библиотек для использования сервисов REST, позвольте мне дать вам точку зрения клиента, почему я думаю, что перенос результата в метаданные - это путь:

  • Без общего счета, как клиент может знать, что он еще не получил все, что есть, и должен продолжать пейджинг через результирующий набор? В пользовательском интерфейсе, который не выполнял перспективу на следующей странице, в худшем случае это может быть представлено как ссылка Next/More, которая на самом деле не извлекала никаких дополнительных данных.
  • Включение метаданных в ответ позволяет клиенту отслеживать меньшее состояние. Теперь мне не нужно сопоставлять свой запрос REST с ответом, так как ответ содержит метаданные, необходимые для восстановления состояния запроса (в данном случае курсора в набор данных).
  • Если состояние является частью ответа, я могу одновременно выполнять несколько запросов в один и тот же набор данных, и я могу обрабатывать запросы в любом порядке, в котором они будут поступать, что не обязательно означает, что я сделал запросы.

И предложение: Как Twitter API, вы должны заменить page_number прямым указателем/курсором. Причина в том, что API позволяет клиенту устанавливать размер страницы за запрос. Является ли возвращаемое число_страницы числом страниц, запрошенным клиентом до сих пор, или номером страницы, данным последним используемым page_size (почти наверняка позже, но почему бы вообще не избежать такой неоднозначности)?

Ответ 3

Я бы порекомендовал добавить заголовки для того же. Перемещение метаданных в заголовки помогает избавиться от таких конвертов, как result, data или records а тело ответа содержит только те данные, которые нам нужны. Вы можете использовать заголовок ссылки, если вы тоже генерируете ссылки на страницы.

    HTTP/1.1 200
    Pagination-Count: 100
    Pagination-Page: 5
    Pagination-Limit: 20
    Content-Type: application/json

    [
      {
        "id": 10,
        "name": "shirt",
        "color": "red",
        "price": "$23"
      },
      {
        "id": 11,
        "name": "shirt",
        "color": "blue",
        "price": "$25"
      }
    ]

За подробностями обращайтесь к:

https://github.com/adnan-kamili/rest-api-response-format

Для файла чванства:

https://github.com/adnan-kamili/swagger-response-template

Ответ 4

Как правило, я делаю простым способом, независимо от того, что я создаю конечную точку restAPI, например "localhost/api/method/: lastIdObtained/: countDateToReturn" с этими параметрами, вы можете сделать это простым запросом. в сервисе, например. .сеть

jsonData function(lastIdObtained,countDatetoReturn){
'... write your code as you wish..'
and into select query make a filter
select top countDatetoreturn tt.id,tt.desc
 from tbANyThing tt
where id > lastIdObtained
order by id
}

В Ionic, когда я прокручиваю снизу вверх, я пропускаю нулевое значение, когда я получаю ответ, я устанавливаю значение последнего полученного идентификатора, и когда я скользлю сверху вниз, я пропускаю последний полученный регистрационный идентификатор