使用Hapi时如何将路由存储在单独的文件中?
How to store routes in separate files when using Hapi?
所有 Hapi 示例(以及 Express 中的类似示例)显示路由都在起始文件中定义:
var Hapi = require('hapi');
var server = new Hapi.Server();
server.connection({ port: 8000 });
server.route({
method: 'GET',
path: '/',
handler: function (request, reply) {
reply('Hello, world!');
}
});
server.route({
method: 'GET',
path: '/{name}',
handler: function (request, reply) {
reply('Hello, ' + encodeURIComponent(request.params.name) + '!');
}
});
server.start(function () {
console.log('Server running at:', server.info.uri);
});
但是,不难想象当使用大量不同的路径实现生产应用程序时,这个文件会增长到多大。因此,我想分解路由,将它们分组并存储在单独的文件中,例如 UserRoutes.js、CartRoutes.js,然后将它们附加到主文件中(添加到服务器对象)。您建议如何将其分开然后添加?
您可以为用户路由创建一个单独的文件(config/routes/user.js
):
module.exports = [
{ method: 'GET', path: '/users', handler: function () {} },
{ method: 'GET', path: '/users/{id}', handler: function () {} }
];
与购物车类似。然后在config/routes
(config/routes/index.js
)中创建索引文件:
var cart = require('./cart');
var user = require('./user');
module.exports = [].concat(cart, user);
然后您可以在主文件中加载此索引文件并调用 server.route()
:
var routes = require('./config/routes');
...
server.route(routes);
或者,对于 config/routes/index.js
,您可以动态加载它们,而不是手动添加路由文件(例如 cart
、user
):
const fs = require('fs');
let routes = [];
fs.readdirSync(__dirname)
.filter(file => file != 'index.js')
.forEach(file => {
routes = routes.concat(require(`./${file}`))
});
module.exports = routes;
您可以使用 require-hapiroutes 为您做一些组织和加载。 (我是作者所以我有点偏见,我写它是为了让我的管理路线更轻松)
我是 require-directory 的忠实粉丝,并且想要一种方法来同样轻松地管理我的路线。这使您可以混合和匹配模块中的路由以及具有路由的目录中的模块。
然后你可以做这样的事情...
var routes = require('./routes');
server.route(routes.routes);
然后在您的目录中,您可以有一个路由文件,例如...
module.exports = [
{
method : 'GET',
path : '/route1',
handler : routeHandler1,
config : {
description: 'my route description',
notes: 'Important stuff to know about this route',
tags : ['app']
}
},
{
method : 'GET',
path : '/route2',
handler : routeHandler2,
config : {
description: 'my route description',
notes: 'Important stuff to know about this route',
tags : ['app']
}
}];
或者,您可以通过分配给模块上的 "routes" 属性 来混合搭配
module.exports.routes = [
{
method : 'GET',
path : '/route1',
handler : routeHandler1,
config : {
description: 'my route description',
notes: 'Important stuff to know about this route',
tags : ['app']
}
},
{
method : 'GET',
path : '/route2',
handler : routeHandler2,
config : {
description: 'my route description',
notes: 'Important stuff to know about this route',
tags : ['app']
}
}];
或者你可以使用一个索引文件来加载所有的路由
在目录
index.js
/**
* Module dependencies.
*/
const fs = require('fs');
const path = require('path');
const basename = path.basename(__filename);
const routes = fs.readdirSync(__dirname)
.filter((file) => {
return (file.indexOf('.') !== 0) && (file !== basename);
})
.map((file) => {
return require(path.join(__dirname, file));
});
module.exports = routes;
同一目录中的其他文件,例如:
module.exports = [
{
method: 'POST',
path: '/api/user',
config: {
}
},
{
method: 'PUT',
path: 'api/user/{userId}',
config: {
}
}
];
比你的 root/index
const Routes = require('./src/routes');
/**
* Add all the routes
*/
for (var route in Routes) {
server.route(Routes[route]);
}
您应该尝试 Glue 插件:https://github.com/hapijs/glue。它允许您模块化您的应用程序。您可以将路由放在单独的子目录中,然后将它们包含为 Hapi.js 插件。您还可以将其他插件(Inert、Vision、Good)包含在 Glue 中,并使用清单对象(或 json 文件)配置您的应用程序。
快速示例:
server.js:
var Hapi = require('hapi');
var Glue = require('glue');
var manifest = {
connections: [{
port: 8080
}],
plugins: [
{ inert: [{}] },
{ vision: [{}] },
{ './index': null },
{
'./api': [{
routes: {
prefix: '/api/v1'
}
}]
}
]
};
var options = {
relativeTo: __dirname + '/modules'
};
Glue.compose(manifest, options, function (err, server) {
server.start(function(err) {
console.log('Server running at: %s://%s:%s', server.info.protocol, server.info.address, server.info.port);
});
});
./modules/index/index.js:
exports.register = function(server, options, next) {
server.route({
method: 'GET',
path: '/',
handler: require('./home')
});
});
exports.register.attributes = {
pkg: require('./package.json')
};
./modules/index/package.json:
{
"name": "IndexRoute",
"version": "1.0.0"
}
./modules/index/home.js:
exports.register = function(req, reply) {
reply.view('home', { title: 'Awesome' });
});
查看 Dave Stevens 的 this 精彩文章,了解更多详细信息和示例。
看到这么多不同的解决方案很有趣,这是另一个。
拯救世界
在我的最新项目中,我决定对具有特定名称模式的文件进行通配,然后将它们一个接一个地请求到服务器中。
创建 server
对象后导入路由
// Construct and setup the server object.
// ...
// Require routes.
Glob.sync('**/*route*.js', { cwd: __dirname }).forEach(function (ith) {
const route = require('./' + ith);
if (route.hasOwnProperty('method') && route.hasOwnProperty('path')) {
console.log('Adding route:', route.method, route.path);
server.route(route);
}
});
// Start the server.
// ...
glob 模式 **/*route*.js
将查找指定当前工作目录内和下面的所有文件,其名称包含单词 route 并以后缀 .js.
文件结构
在 globbing 的帮助下,我们在 server
对象和它的路由之间建立了松耦合。只需添加新的路由文件,它们将在您下次重新启动服务器时包含在内。
我喜欢根据路径构建路由文件,并使用 HTTP 方法命名它们,如下所示:
server.js
routes/
users/
get-route.js
patch-route.js
put-route.js
articles/
get-route.js
patch-route.js
put-route.js
示例路由文件routes/users/get-route.js
module.exports = {
method: 'GET',
path: '/users',
config: {
description: 'Fetch users',
// ...
},
handler: function (request, reply) {
// ...
}
};
最后的想法
遍历和遍历文件并不是一个特别快的过程,因此缓存层可能值得根据您的情况在生产构建中进行研究。
尝试 hapi-auto-route 插件!使用起来非常简单,并允许在您的路由路径中添加前缀。
完全披露:我是这个插件的作者
我知道这已经获得批准。我放下了我的解决方案,以防有人想要快速修复并且是 Hapi 的新手。
我也包含了一些 NPM,这样新手可以看到如何在案例中使用 server.register
和多个插件 ( good
+ hapi-auto-route
)
安装了一些 npm 包:
npm i -S hapi-auto-route
npm i -S good-console
npm i -S good
// server.js
'use strict';
const Hapi = require('hapi');
const Good = require('good');
const AutoRoute = require('hapi-auto-route');
const server = new Hapi.Server();
server.connection(
{
routes: { cors: true },
port: 3000,
host: 'localhost',
labels: ['web']
}
);
server.register([{
register: Good,
options: {
reporters: {
console: [{
module: 'good-squeeze',
name: 'Squeeze',
args: [{
response: '*',
log: '*'
}]
}, {
module: 'good-console'
}, 'stdout']
}
}
}, {
register: AutoRoute,
options: {}
}], (err) => {
if (err) {
throw err; // something bad happened loading the plugin
}
server.start((err) => {
if (err) {
throw err;
}
server.log('info', 'Server running at: ' + server.info.uri);
});
});
在你的routes/user.js
module.exports =
[
{
method: 'GET',
path: '/',
handler: (request, reply) => {
reply('Hello, world!');
}
},
{
method: 'GET',
path: '/another',
handler: (request, reply) => {
reply('Hello, world again!');
}
},
];
现在运行:node server.js
干杯
所有 Hapi 示例(以及 Express 中的类似示例)显示路由都在起始文件中定义:
var Hapi = require('hapi');
var server = new Hapi.Server();
server.connection({ port: 8000 });
server.route({
method: 'GET',
path: '/',
handler: function (request, reply) {
reply('Hello, world!');
}
});
server.route({
method: 'GET',
path: '/{name}',
handler: function (request, reply) {
reply('Hello, ' + encodeURIComponent(request.params.name) + '!');
}
});
server.start(function () {
console.log('Server running at:', server.info.uri);
});
但是,不难想象当使用大量不同的路径实现生产应用程序时,这个文件会增长到多大。因此,我想分解路由,将它们分组并存储在单独的文件中,例如 UserRoutes.js、CartRoutes.js,然后将它们附加到主文件中(添加到服务器对象)。您建议如何将其分开然后添加?
您可以为用户路由创建一个单独的文件(config/routes/user.js
):
module.exports = [
{ method: 'GET', path: '/users', handler: function () {} },
{ method: 'GET', path: '/users/{id}', handler: function () {} }
];
与购物车类似。然后在config/routes
(config/routes/index.js
)中创建索引文件:
var cart = require('./cart');
var user = require('./user');
module.exports = [].concat(cart, user);
然后您可以在主文件中加载此索引文件并调用 server.route()
:
var routes = require('./config/routes');
...
server.route(routes);
或者,对于 config/routes/index.js
,您可以动态加载它们,而不是手动添加路由文件(例如 cart
、user
):
const fs = require('fs');
let routes = [];
fs.readdirSync(__dirname)
.filter(file => file != 'index.js')
.forEach(file => {
routes = routes.concat(require(`./${file}`))
});
module.exports = routes;
您可以使用 require-hapiroutes 为您做一些组织和加载。 (我是作者所以我有点偏见,我写它是为了让我的管理路线更轻松)
我是 require-directory 的忠实粉丝,并且想要一种方法来同样轻松地管理我的路线。这使您可以混合和匹配模块中的路由以及具有路由的目录中的模块。
然后你可以做这样的事情...
var routes = require('./routes');
server.route(routes.routes);
然后在您的目录中,您可以有一个路由文件,例如...
module.exports = [
{
method : 'GET',
path : '/route1',
handler : routeHandler1,
config : {
description: 'my route description',
notes: 'Important stuff to know about this route',
tags : ['app']
}
},
{
method : 'GET',
path : '/route2',
handler : routeHandler2,
config : {
description: 'my route description',
notes: 'Important stuff to know about this route',
tags : ['app']
}
}];
或者,您可以通过分配给模块上的 "routes" 属性 来混合搭配
module.exports.routes = [
{
method : 'GET',
path : '/route1',
handler : routeHandler1,
config : {
description: 'my route description',
notes: 'Important stuff to know about this route',
tags : ['app']
}
},
{
method : 'GET',
path : '/route2',
handler : routeHandler2,
config : {
description: 'my route description',
notes: 'Important stuff to know about this route',
tags : ['app']
}
}];
或者你可以使用一个索引文件来加载所有的路由 在目录
index.js
/**
* Module dependencies.
*/
const fs = require('fs');
const path = require('path');
const basename = path.basename(__filename);
const routes = fs.readdirSync(__dirname)
.filter((file) => {
return (file.indexOf('.') !== 0) && (file !== basename);
})
.map((file) => {
return require(path.join(__dirname, file));
});
module.exports = routes;
同一目录中的其他文件,例如:
module.exports = [
{
method: 'POST',
path: '/api/user',
config: {
}
},
{
method: 'PUT',
path: 'api/user/{userId}',
config: {
}
}
];
比你的 root/index
const Routes = require('./src/routes');
/**
* Add all the routes
*/
for (var route in Routes) {
server.route(Routes[route]);
}
您应该尝试 Glue 插件:https://github.com/hapijs/glue。它允许您模块化您的应用程序。您可以将路由放在单独的子目录中,然后将它们包含为 Hapi.js 插件。您还可以将其他插件(Inert、Vision、Good)包含在 Glue 中,并使用清单对象(或 json 文件)配置您的应用程序。
快速示例:
server.js:
var Hapi = require('hapi');
var Glue = require('glue');
var manifest = {
connections: [{
port: 8080
}],
plugins: [
{ inert: [{}] },
{ vision: [{}] },
{ './index': null },
{
'./api': [{
routes: {
prefix: '/api/v1'
}
}]
}
]
};
var options = {
relativeTo: __dirname + '/modules'
};
Glue.compose(manifest, options, function (err, server) {
server.start(function(err) {
console.log('Server running at: %s://%s:%s', server.info.protocol, server.info.address, server.info.port);
});
});
./modules/index/index.js:
exports.register = function(server, options, next) {
server.route({
method: 'GET',
path: '/',
handler: require('./home')
});
});
exports.register.attributes = {
pkg: require('./package.json')
};
./modules/index/package.json:
{
"name": "IndexRoute",
"version": "1.0.0"
}
./modules/index/home.js:
exports.register = function(req, reply) {
reply.view('home', { title: 'Awesome' });
});
查看 Dave Stevens 的 this 精彩文章,了解更多详细信息和示例。
看到这么多不同的解决方案很有趣,这是另一个。
拯救世界
在我的最新项目中,我决定对具有特定名称模式的文件进行通配,然后将它们一个接一个地请求到服务器中。
创建 server
对象后导入路由
// Construct and setup the server object.
// ...
// Require routes.
Glob.sync('**/*route*.js', { cwd: __dirname }).forEach(function (ith) {
const route = require('./' + ith);
if (route.hasOwnProperty('method') && route.hasOwnProperty('path')) {
console.log('Adding route:', route.method, route.path);
server.route(route);
}
});
// Start the server.
// ...
glob 模式 **/*route*.js
将查找指定当前工作目录内和下面的所有文件,其名称包含单词 route 并以后缀 .js.
文件结构
在 globbing 的帮助下,我们在 server
对象和它的路由之间建立了松耦合。只需添加新的路由文件,它们将在您下次重新启动服务器时包含在内。
我喜欢根据路径构建路由文件,并使用 HTTP 方法命名它们,如下所示:
server.js
routes/
users/
get-route.js
patch-route.js
put-route.js
articles/
get-route.js
patch-route.js
put-route.js
示例路由文件routes/users/get-route.js
module.exports = {
method: 'GET',
path: '/users',
config: {
description: 'Fetch users',
// ...
},
handler: function (request, reply) {
// ...
}
};
最后的想法
遍历和遍历文件并不是一个特别快的过程,因此缓存层可能值得根据您的情况在生产构建中进行研究。
尝试 hapi-auto-route 插件!使用起来非常简单,并允许在您的路由路径中添加前缀。
完全披露:我是这个插件的作者
我知道这已经获得批准。我放下了我的解决方案,以防有人想要快速修复并且是 Hapi 的新手。
我也包含了一些 NPM,这样新手可以看到如何在案例中使用 server.register
和多个插件 ( good
+ hapi-auto-route
)
安装了一些 npm 包:
npm i -S hapi-auto-route
npm i -S good-console
npm i -S good
// server.js
'use strict';
const Hapi = require('hapi');
const Good = require('good');
const AutoRoute = require('hapi-auto-route');
const server = new Hapi.Server();
server.connection(
{
routes: { cors: true },
port: 3000,
host: 'localhost',
labels: ['web']
}
);
server.register([{
register: Good,
options: {
reporters: {
console: [{
module: 'good-squeeze',
name: 'Squeeze',
args: [{
response: '*',
log: '*'
}]
}, {
module: 'good-console'
}, 'stdout']
}
}
}, {
register: AutoRoute,
options: {}
}], (err) => {
if (err) {
throw err; // something bad happened loading the plugin
}
server.start((err) => {
if (err) {
throw err;
}
server.log('info', 'Server running at: ' + server.info.uri);
});
});
在你的routes/user.js
module.exports =
[
{
method: 'GET',
path: '/',
handler: (request, reply) => {
reply('Hello, world!');
}
},
{
method: 'GET',
path: '/another',
handler: (request, reply) => {
reply('Hello, world again!');
}
},
];
现在运行:node server.js
干杯