npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

hapi-api-version

v2.3.1

Published

An API versioning plugin for hapi.

Downloads

18,597

Readme

hapi-api-version

Lead Maintainer: Tim Costa

Build Status

An API versioning plugin for hapi v17 onwards.

Features / Goals

  • Supports versioning via accept and custom header (default api-version) as described on troyhunt.com
  • 100% test coverage
  • Easy to use and flexible
  • Follows the hapi coding conventions
  • Allows to follow the DRY principle

Requirements

Runs with Node >=8 and hapi >=17 which is tested with Travis CI.

Installation

npm install --save hapi-api-version

Usage

Register it with the server:

'use strict';

const Hapi = require('hapi');

const init = async function () {
    try {
        const server = new Hapi.server({ port: 3000 });
        await server.register({
            register: require('hapi-api-version'),
            options: {
                validVersions: [1, 2],
                defaultVersion: 2,
                vendorName: 'mysuperapi'
            }
        })
        await server.start();
        console.log('Server running at:', server.info.uri);
    }   
    catch (err) {
        console.error(err);
        process.exit(1);
    }
}
init();

Time to add some routes...

There are typically two common use cases which this plugin is designed to address.

Unversioned routes

This is the type of routes which never change regardless of the api version. The route definition and the handler stay the same.

server.route({
    method: 'GET',
    path:'/loginStatus',
    handler: function (request, h) {

        const loggedIn = ...;

        return {
          loggedIn: loggedIn
        };
    }
});

Versioned routes

This is the type of routes which actually change.

Handler only

In simple cases where just the handler differs you could use this approach.

const usersVersion1 = [{
    name: 'Peter Miller'
}];

const usersVersion2 = [{
    firtname: 'Peter',
    lastname: 'Miller'
}];

server.route({
    method: 'GET',
    path: '/users',
    handler: function (request, h) {

        const version = request.pre.apiVersion;

        if (version === 1) {
            return usersVersion1;
        }

        return usersVersion2;
    }
});
Different route definitions per version

Sometimes it is required to change not just the handler but also the route definition itself.

const usersVersion1 = [{
    name: 'Peter Miller'
}];

const usersVersion2 = [{
    firtname: 'Peter',
    lastname: 'Miller'
}];

server.route({
    method: 'GET',
    path: '/v1/users',
    handler: function (request, h) {

        return usersVersion1;
    },
    config: {
        response: {
            schema: Joi.array().items(
                Joi.object({
                    name: Joi.string().required()
                })
            )
        }
    }
});

server.route({
    method: 'GET',
    path: '/v2/users',
    handler: function (request, h) {

        return usersVersion2;
    },
    config: {
        response: {
            schema: Joi.array().items(
                Joi.object({
                    firtname: Joi.string().required(),
                    lastname: Joi.string().required()
                })
            )
        }
    }

});

Note the different schemas for response validation here.

The user still sends a request to /users and the plugin rewrites it internally to either /v1/users or /v2/users based on the requested version.

Example

A complete working example with routes can be found in the example folder.

Documentation

hapi-api-version works internally with rewriting urls. The process is very simple:

  1. Check if an accept header OR a custom header (default api-version) is present and extract the version
  2. If a version was extracted check if it is valid, otherwise respond with a status code 400
  3. If no version was extracted (e.g. no headers sent) use the default version
  4. Check if a versioned route (like /v2/users) exists -> if so rewrite the url from /users to /v2/users, otherwise do nothing

Options

The options for the plugin are validated on plugin registration.

  • validVersions (required) is an array of integer values. Specifies all valid api versions you support. Anything else will be considered invalid and the plugin responds with a status code 400.
  • defaultVersion (required) is an integer that is included in validVersions. Defines which version to use if no headers are sent.
  • vendorName (required) is a string. Defines the vendor name used in the accept header.
  • versionHeader (optional) is a string. Defines the name of the custom header to use. Per default this is api-version.
  • passiveMode (optional) is a boolean. Allows to bypass when no headers are supplied. Useful when you serve other content like documentation and reduces overhead on processing those.
  • basePath (optional) is a string. In case we have a base path different from / (example: /api/). Per default this is /.

Getting the requested API version in the handler

You can get the API version requested by the user (or maybe the default version if nothing was requested) in the handler. It is stored in request.pre.apiVersion.

Headers

The headers must have a specific format to be correctly recognized and processed by the plugin.

Accept header
Accept: application/vnd.mysuperapi.v2+json

Here mysuperapi is what was specified in options as vendorName. If the vendor name does not match, the default version will be used instead.

Custom header
api-version: 2

Here api-version is the default name of the custom header. It can be specified in the options via versionHeader.

Running the tests

lab is used for all tests. Make sure you install it globally before running the tests:

npm install -g lab

Now just execute the tests:

npm test

To see the coverage report in html just execute:

npm run test-coverage

After this the html report can be found in coverage/coverage.html.

License

Apache-2.0