123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- /*
- * This file is part of the storage node for the Joystream project.
- * Copyright (C) 2019 Joystream Contributors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- 'use strict'
- const debug = require('debug')('joystream:middleware:pagination')
- // Pagination definitions
- const apiDefs = {
- parameters: {
- paginationLimit: {
- name: 'limit',
- in: 'query',
- description: 'Number of items per page.',
- required: false,
- schema: {
- type: 'integer',
- minimum: 1,
- maximum: 50,
- default: 20,
- },
- },
- paginationOffset: {
- name: 'offset',
- in: 'query',
- description: 'Page number (offset)',
- schema: {
- type: 'integer',
- minimum: 0,
- },
- },
- },
- schemas: {
- PaginationInfo: {
- type: 'object',
- required: ['self'],
- properties: {
- self: {
- type: 'string',
- },
- next: {
- type: 'string',
- },
- prev: {
- type: 'string',
- },
- first: {
- type: 'string',
- },
- last: {
- type: 'string',
- },
- },
- },
- },
- }
- /**
- * Silly pagination because it's faster than getting other modules to work.
- *
- * Usage:
- * - apiDoc.parameters = pagination.parameters
- * -> Validates pagination parameters
- * - apiDoc.responses.200.schema.pagination = pagination.response
- * -> Generates pagination info on response
- * - paginate(req, res, [lastOffset])
- * -> add (valid) pagination fields to response object
- * If lastOffset is given, create a last link with that offset
- **/
- module.exports = {
- // Add pagination parameters and pagination info responses.
- parameters: [
- { $ref: '#/components/parameters/paginationLimit' },
- { $ref: '#/components/parameters/paginationOffset' },
- ],
- response: {
- $ref: '#/components/schema/PaginationInfo',
- },
- // Update swagger/openapi specs with our own parameters and definitions
- openapi(api) {
- api.components = api.components || {}
- api.components.parameters = { ...(api.components.parameters || {}), ...apiDefs.parameters }
- api.components.schemas = { ...(api.components.schemas || {}), ...apiDefs.schemas }
- return api
- },
- // Pagination function
- paginate(req, res, lastOffset) {
- // Skip if the response is not an object.
- if (Object.prototype.toString.call(res) !== '[object Object]') {
- debug('Cannot paginate non-objects.')
- return res
- }
- // Defaults for parameters
- const offset = req.query.offset || 0
- const limit = req.query.limit || 20
- debug('Create pagination links from offset=' + offset, 'limit=' + limit)
- // Parse current url
- const url = require('url')
- // Disable lint because the code (and tests) relied upon obsolete UrlObject. Remove after migration to TypeScript.
- // eslint-disable-next-line node/no-deprecated-api
- const reqUrl = url.parse(req.protocol + '://' + req.get('host') + req.originalUrl)
- const params = new url.URLSearchParams(reqUrl.query)
- // Pagination object
- const pagination = {
- self: reqUrl.href,
- }
- const prev = offset - limit
- if (prev >= 0) {
- params.set('offset', prev)
- reqUrl.search = params.toString()
- pagination.prev = url.format(reqUrl)
- }
- const next = offset + limit
- if (next >= 0) {
- params.set('offset', next)
- reqUrl.search = params.toString()
- pagination.next = url.format(reqUrl)
- }
- if (lastOffset) {
- params.set('offset', lastOffset)
- reqUrl.search = params.toString()
- pagination.last = url.format(reqUrl)
- }
- // First
- params.set('offset', 0)
- reqUrl.search = params.toString()
- pagination.first = url.format(reqUrl)
- debug('pagination', pagination)
- // Now set pagination values in response.
- res.pagination = pagination
- return res
- },
- }
|