Hapi API Versioning Plugin
hapi-api-version is a plugin designed for the Hapi.js framework (v17 onwards) to facilitate API versioning. It allows developers to manage different API versions by supporting versioning via the `Accept` header or a custom header (defaulting to `api-version`). The plugin internally rewrites URLs based on the requested API version, enabling both handler-only versioning and distinct route definitions per version, including separate response schemas. The latest version, 2.3.1, was last published 7 years ago, making it compatible only with older Hapi.js ecosystems (specifically Hapi v17.x). It does not receive active updates for modern Hapi versions (v20+ or v21+), implying a halted release cadence and limited applicability for current Hapi projects.
Common errors
-
Cannot read properties of undefined (reading 'register') or server.register is not a function
cause Attempting to use a Hapi.js version incompatible with the plugin's API, or incorrect plugin registration syntax.fixEnsure you are using `@hapi/hapi` version `17.x.x` as a peer dependency, and that `server.register` is called with an object containing a `plugin` key set to the required module and an `options` key. Check Hapi's migration guide if moving between major versions. -
Error: Plugin options validation failed
cause Missing or invalid required options during plugin registration, such as `validVersions`, `defaultVersion`, or `vendorName`.fixProvide all required options (`validVersions` as an array of integers, `defaultVersion` as an integer within `validVersions`, and `vendorName` as a string) during plugin registration. Refer to the plugin's documentation for option specifics. -
UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: X)
cause Hapi server startup or plugin registration failed silently due to an unhandled promise rejection, often related to port conflicts or other initialization errors.fixWrap your `init` function call or the `server.start()` and `server.register()` calls in a `try...catch` block to properly log and handle errors during server initialization. Ensure the port is not already in use.
Warnings
- breaking This plugin is strictly compatible with Hapi.js versions 17.x.x. It is not maintained for or compatible with newer Hapi versions (e.g., v20, v21+), which have introduced significant breaking changes and ESM support.
- gotcha The plugin relies on `accept` headers (with `vendorName`) or a custom header (default `api-version`) to determine the requested API version. If neither is present, it defaults to the `defaultVersion` specified in the options. Clients must correctly provide one of these headers.
- gotcha The `hapi-api-version` plugin achieves versioning by internally rewriting requested URLs (e.g., `/users` to `/v1/users`). Developers defining versioned routes must ensure their route paths match this rewritten format (e.g., `/v1/users` and `/v2/users`) for the plugin to function correctly.
- deprecated The package `hapi-api-version` has not been updated in 7 years. Its last stable version (2.3.1) targets Hapi.js v17.x. This indicates the package is effectively abandoned and not maintained for contemporary Node.js or Hapi.js versions.
Install
-
npm install hapi-api-version -
yarn add hapi-api-version -
pnpm add hapi-api-version
Imports
- hapiApiVersion
import hapiApiVersion from 'hapi-api-version';
const hapiApiVersion = require('hapi-api-version'); - Plugin Registration
await server.register(hapiApiVersion, { options: { validVersions: [1, 2] } });await server.register({ plugin: require('hapi-api-version'), options: { validVersions: [1, 2], defaultVersion: 2, vendorName: 'mysuperapi' } });
Quickstart
'use strict';
const Hapi = require('@hapi/hapi');
const hapiApiVersion = require('hapi-api-version');
const init = async function () {
try {
const server = new Hapi.server({ port: 3000 });
await server.register({
plugin: hapiApiVersion,
options: {
validVersions: [1, 2],
defaultVersion: 2,
vendorName: 'mysuperapi'
}
})
server.route({
method: 'GET',
path: '/users',
handler: function (request, h) {
const version = request.pre.apiVersion;
if (version === 1) {
return [{ name: 'Peter Miller' }];
}
return [{ firtname: 'Peter', lastname: 'Miller' }];
}
});
server.route({
method: 'GET',
path: '/loginStatus',
handler: function (request, h) {
return { loggedIn: true };
}
});
await server.start();
console.log('Server running at:', server.info.uri);
}
catch (err) {
console.error('Server startup error:', err);
process.exit(1);
}
};
init();