Как хранить маршруты в отдельных файлах при использовании 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, а затем прикрепить их в основной файл (добавить к объекту сервера). Как бы вы предложили отделить это, а затем добавить?
7 ответов
Вы можете создать отдельный файл для пользовательских маршрутов (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;
Вы должны попробовать плагин Glue: https://github.com/hapijs/glue. Это позволяет вам модулировать ваше приложение. Вы можете разместить свои маршруты в отдельных подкаталогах, а затем включить их в виде плагинов Hapi.js. Вы также можете включить в Glue другие плагины (Inert, Vision, Good), а также настроить свое приложение с помощью объекта манифеста (или файла 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' });
});
Взгляните на эту замечательную статью Дэйва Стивенса для более подробной информации и примеров.
Вы можете использовать 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']
}
}];
Или вы можете смешивать и сопоставлять, присваивая свойству "маршруты" в модуле
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']
}
}];
Всегда хорошо иметь варианты. Для этого есть полная документация на сайте github или npmjs.
Или вы можете использовать индексный файл для загрузки всех маршрутов в каталоге
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: {
}
}
];
и чем в вашем корне / индексе
const Routes = require('./src/routes');
/**
* Add all the routes
*/
for (var route in Routes) {
server.route(Routes[route]);
}
Интересно увидеть так много разных решений, вот еще одно.
Глоб на помощь
Для моего последнего проекта я остановился на поиске файлов с определенным шаблоном имени, а затем требовал их одного за другим на сервер.
Импортировать маршруты после создания 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.
// ...
Образец шара **/*route*.js
найдет все файлы внутри и ниже указанного текущего рабочего каталога с именем, которое содержит слово route и заканчивается суффиксом .js.
Файловая структура
С помощью шатания мы имеем слабую связь между 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! Это очень просто использовать и разрешить префикс в вашем пути маршрута.
Я знаю, что это уже одобрено. Я записал свое решение на тот случай, если кто-то захочет быстро исправить ситуацию и познакомиться с Хапи.
Также я включил несколько 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
ура