Как хранить маршруты в отдельных файлах при использовании 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, а затем прикрепить их к основному файлу (добавить в объект сервера). Как бы вы предложили разделить это, а затем добавить?


person Centurion    schedule 04.01.2015    source источник


Ответы (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;
person Gergo Erdosi    schedule 04.01.2015
comment
Обратите внимание, что то, что Gergo делает здесь, это просто стандартный Javascript, не относящийся к Hapi. - person lawrence; 11.09.2015
comment
и что, если у меня есть какие-то проверки Joi или глобальные переменные в моих внешних обработчиках? должен ли я включать require('joi') в каждый внешний файл? - person Magico; 22.04.2016
comment
@Magico для библиотеки Joi вам нужно будет включить его в каждый внешний файл. Глобальные переменные будут работать так же, поэтому у вас все еще будет доступ к ним в модулях required. - person adam-beck; 23.05.2016
comment
чистый, классический, лучший способ до сих пор. - person Achmad Naufal Syafiq; 18.09.2017
comment
Работает как шарм .. Спасибо - person CodeHacker; 03.11.2017
comment
В моем проекте я использовал ключевое слово import в файле index.js для получения внешних маршрутов. это не сработало. Затем я использовал require, это сработало. Я хотел бы знать, почему это не сработало с импортом. В чем разница между require и import. почему это не работало с импортом. - person nzhmz; 01.12.2017

Вам следует попробовать подключаемый модуль Glue: https://github.com/hapijs/glue. Это позволяет вам модульизировать ваше приложение. Вы можете разместить свои маршруты в отдельных подкаталогах, а затем включить их в качестве плагинов Hapi.js. Вы также можете включить другие плагины (Inert, Vision, Good) с Glue, а также настроить свое приложение с помощью объекта манифеста (или файла json).

Быстрый пример:

сервер.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' });
});

Взгляните на эту замечательную статью Дэйва Стивенса для больше подробностей и примеров.

person coquin    schedule 29.10.2015

Вы можете использовать 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.

person Brian ONeil    schedule 19.10.2015
comment
@AlanDong рад, что помог тебе. - person Brian ONeil; 21.03.2017

или вы можете использовать индексный файл для загрузки всех маршрутов в каталоге

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]);
}
person Whisher    schedule 20.10.2015

Интересно видеть столько разных решений, вот еще одно.

Глоббинг на помощь

Для моего последнего проекта я решил использовать подстановку файлов с определенным шаблоном имени, а затем запрашивать их на сервере один за другим.

Импортируйте маршруты после создания объекта 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.

Структура файла

С помощью подстановки у нас есть слабая связь между объектом 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) {
        // ...
    }
};

Последние мысли

Подстановка и итерация по файлам — не особенно быстрый процесс, поэтому в зависимости от ваших обстоятельств может быть полезно изучить уровень кэширования в производственных сборках.

person Fredric    schedule 25.03.2016

Попробуйте плагин hapi-auto-route! Он очень прост в использовании и позволяет использовать префикс в пути маршрута.

Полное раскрытие: я являюсь автором этого плагина

person sitrakay    schedule 04.04.2017

Я знаю, что это уже одобрено. Я написал свое решение на случай, если кому-то понадобится быстрое исправление и новичок в 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

Ваше здоровье

person Mr H    schedule 17.08.2017