【问题标题】:How to store routes in separate files when using Hapi?使用 Hapi 时如何将路由存储在单独的文件中?
【发布时间】:2015-03-02 05:29:45
【问题描述】:

所有 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,然后将它们附加到主文件中(添加到服务器对象)。您如何建议将其分开然后添加?

【问题讨论】:

    标签: node.js routes hapijs


    【解决方案1】:

    您可以为用户路由创建单独的文件 (config/routes/user.js):

    module.exports = [
        { method: 'GET', path: '/users', handler: function () {} },
        { method: 'GET', path: '/users/{id}', handler: function () {} }
    ];
    

    与购物车类似。然后在config/routesconfig/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,您可以动态加载它们,而不是手动添加路由文件(例如cartuser):

    const fs = require('fs');
    
    let routes = [];
    
    fs.readdirSync(__dirname)
      .filter(file => file != 'index.js')
      .forEach(file => {
        routes = routes.concat(require(`./${file}`))
      });
    
    module.exports = routes;
    

    【讨论】:

    • 请注意,Gergo 在这里所做的只是标准 Javascript,并非特定于 Hapi。
    • 如果我的外部处理程序中有一些 Joi 验证或全局变量怎么办?我应该在每个外部文件中包含 require('joi') 吗?
    • @Magico 对于 Joi 库,您需要将它包含在每个外部文件中。全局变量的工作方式相同,因此您仍然可以在 required 模块中访问它们。
    • 干净、经典、迄今为止最好的方式。
    • 像魅力一样工作......谢谢
    【解决方案2】:

    您应该尝试 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' });
    });
    

    查看this Dave Stevens 的精彩文章,了解更多详细信息和示例。

    【讨论】:

      【解决方案3】:

      您可以使用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']
        }
      }];
      

      总是,很高兴有选择。在githubnpmjs 网站上有完整的文档。

      【讨论】:

      • @AlanDong 很高兴它对您有所帮助。
      【解决方案4】:

      或者您可以使用索引文件来加载所有路由 在目录中

      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]);
      }
      

      【讨论】:

        【解决方案5】:

        看到这么多不同的解决方案很有趣,这是另一个。

        全球救援

        对于我的最新项目,我决定使用特定名称模式查找文件,然后将它们一个一个地请求到服务器中。

        在创建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) {
                // ...
            }
        };
        

        最后的想法

        对文件进行通配和迭代并不是一个特别快的过程,因此根据您的具体情况,缓存层可能值得在生产版本中进行研究。

        【讨论】:

          【解决方案6】:

          试试hapi-auto-route 插件!它使用起来非常简单,并且允许在您的路由路径中添加前缀。

          完全披露:我是这个插件的作者

          【讨论】:

            【解决方案7】:

            我知道这已经获得批准。我写下了我的解决方案,以防有人想要快速修复和新的 Hapi。

            我还包括了一些 NPM,以便 Newbees 可以看到如何在案例中使用带有多个插件的 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

            干杯

            【讨论】:

              猜你喜欢
              • 2015-09-22
              • 1970-01-01
              • 2016-08-07
              • 2014-07-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多