@adam-26/hapi-api-version 中文文档教程

发布于 8年前 浏览 7 项目主页 更新于 3年前

hapi-api-version

Build Status

hapi 的 API 版本控制插件。

分叉自:https://github.com/p-meier/hapi-api-version

Features / Goals

  • Supports versioning using mediaTypes defined via accept header, as described by the media type specification and used on github.com
  • Allows custom function to extract the version number from a request
  • Allows the plugin to be registered multiple times (for example, you could apply the plugin multiple times - each with a custom function to provide multiple options to specify an api version, such as querystring, url path and the default mediaType accept header)
  • 100% test coverage
  • Easy to use and flexible
  • Follows the hapi coding conventions
  • Allows to follow the DRY principle

Requirements

使用 Node >=4 和 hapi >=10 运行,已使用 Travis CI 进行测试。

A note about creating media type headers

如果您创建自定义媒体类型,请务必将其注册到 iana

Installation

npm install --save @adam-26/hapi-api-version

Usage

将其注册到服务器:

import * as HapiApiVersionPlugin from '@adam-26/hapi-api-version';

const Hapi = require('hapi');

const server = new Hapi.Server();
server.connection({
    port: 3000
});

const validVersions = [1, 2];
const defaultVersion = 2;

server.register([{
    register: HapiApiVersionPlugin,
    options: {
        validVersions: validVersions,
        defaultVersion: defaultVersion,
        vendorName: 'mysuperapi'
    }
}, {
       register: HapiApiVersionPlugin,
       options: {
           validVersions: validVersions,
           defaultVersion: defaultVersion,
           descriptor: 'querystring',
           getVersion: (request, options) => {

                   // Extract the version from the querystring parameter 'version'
                   if (request.query.version) {
                       return parseInt(request.query.version);
                   }

                   return null;
           }
       }
}], (err) => {

    //Add routes here...

    server.start((err) => {
        console.log('Server running at:', server.info.uri);
    });
});

时间到添加一些路由……

这个插件旨在解决两个常见的用例。

Unversioned routes

这是无论 api 版本如何都不会改变的路由类型。 路由定义和处理程序保持不变。 没有 request.plugins['hapi-api-version'] 数据可用于未版本化的路由。

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

        return reply({
          status: 'healthy'
        });
    }
});

Versioned routes

这是实际改变的路线类型。

Different route definitions per version

每个路由定义都是特定于版本的。

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

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

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

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

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

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

});

请注意此处响应验证的不同模式。

用户仍然向 /users 发送请求,插件根据要求的版本。

Example

可以在 example 文件夹中找到带有路由的完整工作示例。

Documentation

hapi-api-version 在内部使用重写 url。 这个过程非常简单:

  1. Check if an accept header OR a custom getVersion function is present and extract the version
  2. If a version was extracted check if it is valid, otherwise respond with a status code 415 (The HTTP response code can be configured)
  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

插件的选项在插件注册时被验证。

  • 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 as defined by invalidVersionErrorCode.
  • defaultVersion (required) is an integer that is included in validVersions. Defines which version to use if no headers are sent.
  • vendorName (required, if no getVersion function defined) is a string. Defines the vendor name used in the accept header.
  • passiveMode (optional) is a boolean. Allows to bypass when no headers are supplied. Useful when you have 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 /.
  • getVersion (required, if no vendorName defined) is a string. Return an integer to define the requested version, or null/undefined if no version was provided.
  • descriptor (optional, required to be unique for multiple plugins) is a string, used to describe the versioning technique. This data is available on the request.plugins['hapi-api-plugin'] object.
  • invalidVersionErrorCode (optional) is a integer, used to respond to invalid versions. Defaults to 415.

注意:必须定义 vendorNamegetVersion 函数之一

Getting the requested API version in the handler

handler: function (request, reply) {

    const pluginData = request.plugins['hapi-api-version'];

    // the API version
    console.log(pluginData.apiVersion);

    // true if the default API version was assigned
    console.log(pluginData.useDefault);

    // the number of plugins used to determine the API version
    console.log(pluginData.count);

    // 'default' if the default API version was assigned,
    // otherwise the descriptor of the plugin used to
    // determine the API version
    console.log(pluginData.descriptor);
    // ...
}

您可以获得用户请求的 API 版本(或者可能是默认版本,如果处理程序中没有任何请求)。 它存储在 request.plugins['hapi-api-version'].apiVersion 中。

Headers

标头必须具有特定格式才能被插件正确识别和处理。

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

这里 mysuperapi 是在选项中指定为 vendorName 的内容。 如果供应商名称不匹配,将使用默认版本。

Custom getVersion function
getVersion: (request, options) => { return parseInt(request.query.version, 10); }

例如,返回查询字符串中定义的版本。

Running the tests

lab 用于所有测试。 确保在运行测试之前全局安装它:

npm install -g lab

现在只需执行测试:

npm test

要查看 html 格式的覆盖率报告,只需执行:

npm run test-coverage

之后,可以在 coverage/coverage.html 中找到 html 报告。

License

阿帕奇-2.0

hapi-api-version

Build Status

An API versioning plugin for hapi.

Forked from: https://github.com/p-meier/hapi-api-version

Features / Goals

  • Supports versioning using mediaTypes defined via accept header, as described by the media type specification and used on github.com
  • Allows custom function to extract the version number from a request
  • Allows the plugin to be registered multiple times (for example, you could apply the plugin multiple times - each with a custom function to provide multiple options to specify an api version, such as querystring, url path and the default mediaType accept header)
  • 100% test coverage
  • Easy to use and flexible
  • Follows the hapi coding conventions
  • Allows to follow the DRY principle

Requirements

Runs with Node >=4 and hapi >=10 which is tested with Travis CI.

A note about creating media type headers

If you create a custom media type, be sure to register it with the iana

Installation

npm install --save @adam-26/hapi-api-version

Usage

Register it with the server:

import * as HapiApiVersionPlugin from '@adam-26/hapi-api-version';

const Hapi = require('hapi');

const server = new Hapi.Server();
server.connection({
    port: 3000
});

const validVersions = [1, 2];
const defaultVersion = 2;

server.register([{
    register: HapiApiVersionPlugin,
    options: {
        validVersions: validVersions,
        defaultVersion: defaultVersion,
        vendorName: 'mysuperapi'
    }
}, {
       register: HapiApiVersionPlugin,
       options: {
           validVersions: validVersions,
           defaultVersion: defaultVersion,
           descriptor: 'querystring',
           getVersion: (request, options) => {

                   // Extract the version from the querystring parameter 'version'
                   if (request.query.version) {
                       return parseInt(request.query.version);
                   }

                   return null;
           }
       }
}], (err) => {

    //Add routes here...

    server.start((err) => {
        console.log('Server running at:', server.info.uri);
    });
});

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. No request.plugins['hapi-api-version'] data is available for unversioned routes.

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

        return reply({
          status: 'healthy'
        });
    }
});

Versioned routes

This is the type of routes which actually change.

Different route definitions per version

Each route definition is version specific.

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

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

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

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

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

        return reply(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 getVersion function is present and extract the version
  2. If a version was extracted check if it is valid, otherwise respond with a status code 415 (The HTTP response code can be configured)
  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 as defined by invalidVersionErrorCode.
  • defaultVersion (required) is an integer that is included in validVersions. Defines which version to use if no headers are sent.
  • vendorName (required, if no getVersion function defined) is a string. Defines the vendor name used in the accept header.
  • passiveMode (optional) is a boolean. Allows to bypass when no headers are supplied. Useful when you have 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 /.
  • getVersion (required, if no vendorName defined) is a string. Return an integer to define the requested version, or null/undefined if no version was provided.
  • descriptor (optional, required to be unique for multiple plugins) is a string, used to describe the versioning technique. This data is available on the request.plugins['hapi-api-plugin'] object.
  • invalidVersionErrorCode (optional) is a integer, used to respond to invalid versions. Defaults to 415.

NOTE: One of vendorName or the getVersion function must be defined

Getting the requested API version in the handler

handler: function (request, reply) {

    const pluginData = request.plugins['hapi-api-version'];

    // the API version
    console.log(pluginData.apiVersion);

    // true if the default API version was assigned
    console.log(pluginData.useDefault);

    // the number of plugins used to determine the API version
    console.log(pluginData.count);

    // 'default' if the default API version was assigned,
    // otherwise the descriptor of the plugin used to
    // determine the API version
    console.log(pluginData.descriptor);
    // ...
}

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.plugins['hapi-api-version'].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 getVersion function
getVersion: (request, options) => { return parseInt(request.query.version, 10); }

For example, to return a version defined in the querystring.

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

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文