Minimalist HALicious pagination reply interface for HapiJS
npm install bissle !node !npm  !npm
---
1. Introduction
2. Installation
3. Usage
4. API
5. Example
6. Testing
7. Contribution
This hapi.js plugin enables an additional response toolkit interface to paginate a response in a RESTful and HAL compliant manner. So the plugin accordingly splices the initial response; extends it with meta information about the count of entries per page, the total count and the current page; adds a link map for HALicious navigation and appends the corresponding Link header. It is not a middleware-like plugin, so you are allowed to control the usage explicitly by yourself. Because of this, it works perfectly in combination with HAL plugins like halacious, as it is shown in the example below.
The modules standard and ava are used to grant a high quality implementation.
#### Compatibility
| Major Release | hapi.js version | node version |
| --- | --- | --- |
| v4 | >=18.4 @hapi/hapi | >=12 |
| v3.1 | >=18.3.1 @hapi/hapi | >=8 |
| v3 | >=18 hapi | >=8 |
| v2 | >=17 hapi | >=8 |
| v1 | >=13 hapi | >=6 |
bissle is the Swabian term for a little bit, it should visualize the sense of pagination.
$ npm install --save bissle
`or clone the repository:
`
$ git clone https://github.com/felixheck/bissle
`Usage
#### Import
First you have to import the module and the peer dependency akaya:
` js
const bissle = require('bissle');
const akaya = require('akaya');
`#### Create Hapi server
Afterwards create your Hapi.js server if not already done:
` js
const hapi = require('@hapi/hapi');
const server = hapi.server({
port: 1337,
host: 'localhost',
});
`#### Registration
Finally register the plugins per
server.register():
` js
await server.register([akaya, bissle]);
await server.start();
`After registering bissle, the hapi.js response toolkit will be decorated with the new method
h.bissle().#### Joi Validation
If you use Joi for request validation, simply add the parameters to the query scheme. The plugin exposes the all bissle related scheme via
server.plugins.bissle.scheme. Alternatively it is possible to enable the allowUnknown option.
The exposed object contains additionally the scheme for plugin related options.API
#### Plugin Options
While the plugin registration it is possible to pass a plugin specific options object:
- options {Object} - The plugin specific options object.
- host {string} - The host to use in the URL
Default: undefined (utilizes request.info.host)
- absolute {boolean} - If the pagination links (not the Link header) should be absolute or not.
Default: false.
- paramNames {Object} - Config object for overriding default parameter names output in the response
- perPage {string} - Parameter name for describing the page limit
Default: per_page
- page {string} - Parameter name for describing the current page
Default: page
- total {string} - Parameter name for describing the total item count
Default: total####
toolkit.bissle(response, [options])An additional response toolkit for paginated responses.
-
response {Object} - The result to be decorated and replied.
- options {Object} - The custom default values.
- key {string} - The access key of response to get the result to be paginated.
Default: 'result'.
- perPage {number} - The default entries per page if none is defined in the query string.
Default: 100.
Range: 1-500.
- total {number} - Overwrite the internally generated total value and avoid data splicing. The passed response get returned without internally done pagination. Just meta information and the Link header get added.
Default: null.
Range: >=0.Example
The following example demonstrates the usage of bissle in combination with mongoose, halacious and various utilities.`js
const hapi = require('@hapi/hapi');
const bissle = require('bissle');
const halacious = require('halacious');
const akaya = require('akaya');
const Boom = require('@hapi/boom');
const _ = require('lodash');
const YourModel = require('./models/yourModel');const server = hapi.server({ port: 1337 });
server.route({
method: 'GET',
path: '/',
config: {
id: 'root',
handler (request, h) {
YourModel.find({}, (err, result) => {
if (err) throw Boom.badRequest(err);
if (!result) throw Boom.notFound();
return h.bissle({ result });
});
},
plugins: {
hal: {
prepare(rep) {
_.forEach(rep.entity.result, task => {
rep.embed('task',
./${task._id}, task);
});
},
ignore: ['result']
}
}
});(async () => {
try {
await server.register([akaya, halacious, {
plugin: bissle,
options: { absolute: false }
}]);
await server.start();
console.log('Server started successfully');
} catch (err) {
console.error(err);
}
})();
`---
Assuming that mongoose's
find() returns the following data as result:`js
[
{
_id: "abc",
title: "abc"
},
{
_id: "def",
title: "def"
},
{
_id: "ghi",
title: "ghi"
},
{
_id: "jkl",
title: "jkl"
},
{
_id: "mno",
title: "mno"
}
]
`---
Requesting the route
/items?page=2&per_page=2, the plugin replies:`js
{
_links: {
self: {
href: "/items?page=2&per_page=2"
},
first: {
href: "/items?per_page=2"
},
prev: {
href: "/items?per_page=2"
},
next: {
href: "/items?page=3&per_page=2"
},
last: {
href: "/items?page=3&per_page=2"
},
},
page: 2,
per_page: 2,
total: 5,
result: [
{
_id: "ghi",
title: "ghi"
},
{
_id: "jkl",
title: "jkl"
}
]
}`Additionally the plugin sets the corresponding
Link header.---
The halacious plugin enables to extend this response to:
`js
{
_links: {
self: {
href: "/items?page=2&per_page=2"
},
first: {
href: "/items?per_page=2"
},
prev: {
href: "/items?per_page=2"
},
next: {
href: "/items?page=3&per_page=2"
},
last: {
href: "/items?page=3&per_page=2"
},
},
page: 2,
per_page: 2,
total: 5,
_embedded: [
{
_links: {
self: {
href: "/items/ghi"
}
},
_id: "ghi",
title: "ghi"
},
{
_links: {
self: {
href: "/items/jkl"
}
},
_id: "jkl",
title: "jkl"
}
]
}`So in the end the combination of bissle and a HAL plugin results in a REST/HAL compliant and paginated response.
Testing
First you have to install all dependencies:
`
$ npm install
`To execute all unit tests once, use:
`
$ npm test
`or to run tests based on file watcher, use:
`
$ npm start
`To get information about the test coverage, use:
`
$ npm run coverage
``Do not forget to add corresponding tests to keep up 100% test coverage.