Пагинация для RESTful API на Swagger Node
В предыдущей статье мы написали на Swagger Node небольшой простенький API для работы с коллекцией книг. Однако там есть нюанс. Предположим, у нас собралась большая библиотека из нескольких десятков тысяч книг. Каждый раз, когда мы делаем запрос GET /books
, наш API отдает полную коллекцию. Это отражается на скорости работы нашего приложения и количестве переданного трафика. Поэтому в этой статье попробуем организовать частичную выдачу книг.
Редактируем API
Для организации постраничной выдачи всех наших книг нам нужно 3 параметра:
count
- общее количество книг в коллекции;limit
- количество книг в одном ответе (показываемых на одной странице);skip
- количество пропущенных книг от начала и до первой из текущей выдачи (количество книг на предыдущих страницах).
Зная эти параметры в клиентском приложении легко можно рассчитать общее количество страниц, номер текущей страницы, номера последних страниц.
skip
и limit
мы будем передавать в качестве параметров запроса. count
должен вернуть в ответе сервер.
В файле swagger.yaml
в самом конце добавим описания параметров:
parameters:
skipParam:
name: skip
in: query
description: number of items to skip
required: false
type: integer
format: int32
minimum: 0
limitParam:
name: limit
in: query
description: max records to return
required: false
type: integer
format: int32
maximum: 100
minimum: 0
Ограничим минимальное значение для skip
и limit
и максимальное значение для limit
. Передавать их будем в query запроса.
Добавим описание схемы для ответа с постраничной выдачей книг в definitions:
:
Books:
properties:
paging:
type: object
properties:
skip:
type: integer
limit:
type: integer
count:
type: integer
data:
type: array
items:
$ref: '#/definitions/Book'
required:
- paging
- data
Как видим, теперь ответ сервера должен содержать объект paging
с параметрами пагинации и массив с книгами data
.
Подправим маршрут GET /books
следующим образом:
get:
description: Return a books list
parameters:
- $ref: "#/parameters/skipParam"
- $ref: "#/parameters/limitParam"
responses:
"200":
description: Success
schema:
$ref: '#/definitions/Books'
# responses may fall through to errors
default:
description: Error
schema:
$ref: "#/definitions/ErrorResponse"
Перезапустим сервер в mock-режиме:
swagger project start -m
и попробуем отправить запрос.
Работает. Можно браться за контроллер.
Модифицируем контроллер
Заменим код функции getAll
на следующий:
function getAll(req, res) {
var skip = req.swagger.params.skip.value ? req.swagger.params.skip.value : 0;
var limit = req.swagger.params.limit.value ? req.swagger.params.limit.value : 10;
Book.find().count(function (err, count) {
Book.find().skip(skip).limit(limit).exec(function (err, books) {
if (err) {
throw err;
} else {
res.json({
paging: {
count: count,
skip: skip,
limit: limit
},
data: books
}
);
}
});
});
}
Сперва считываем параметры skip
и limit
и присваиваем значения по умолчанию, если они не заданы. Затем выполняем запрос в БД для определения общего количества книг count
. А потом с заданными параметрами делаем соответствующую выборку книг из БД и отдаем ответ клиенту.
Убедимся, что в swagger.yaml для GET /books
задан operationId: getAll
. Создадим несколько книг методом POST /books
и попробуем поиграться с параметрами пагинации.
Посмотреть код целиком можно в
этой ветке на гитхабе.
Можете критиковать.