How to store routes in separate files when using Hapi?

本小妞迷上赌 提交于 2019-12-02 14:17:20
Gergo Erdosi

You can create a separate file for user routes (config/routes/user.js):

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

Similarly with cart. Then create an index file in config/routes (config/routes/index.js):

var cart = require('./cart');
var user = require('./user');

module.exports = [].concat(cart, user);

You can then load this index file in the main file and call server.route():

var routes = require('./config/routes');

...

server.route(routes);

Alternatively, for config/routes/index.js, instead of adding the route files (e.g. cart, user) manually, you can load them dynamically:

const fs = require('fs');

let routes = [];

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

module.exports = routes;

You should try Glue plugin: https://github.com/hapijs/glue. It allows you to modularize your application. You can place your routes in separate subdirectories and then include them as Hapi.js plugins. You can also include other plugins (Inert, Vision, Good) with Glue as well as configure your application with a manifest object (or json file).

Quick exapmple:

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

Have a look at this wonderful article by Dave Stevens for more details and examples.

You can use require-hapiroutes to do some of the organization and loading for you. (I am the author so I am a little biased, I wrote it to make my life easier in managing routes)

I am a big fan of require-directory and and wanted a way to manage my routes just as easily. This lets you mix and match routes in your modules and modules in directories with routes.

You can then do something like this...

var routes = require('./routes');
server.route(routes.routes);

Then in your directory you could have a route file like...

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

Or, you can mix and match by assigning to a "routes" property on the module

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

Always, good to have options. There is full documentation on the github or npmjs site for it.

or you can use a index file to load all the routes in the directory

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;

other files in the same directory like:

module.exports =  [
    {
        method: 'POST',
        path:  '/api/user',
        config: {

        }
    },
    {
        method: 'PUT',
        path:  'api/user/{userId}',
        config: {

        }
    }
];

and than in your root/index

const Routes = require('./src/routes');
/**
* Add all the routes
*/
for (var route in Routes) {
    server.route(Routes[route]);
}

Interesting to see so many different solutions, here is another one.

Globbing to the rescue

For my latest project I settled on globbing for files with a particular name pattern and then requiring them into the server one by one.

Import routes after having created the server object

// 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.
// ...

The glob pattern **/*route*.js will find all files within and below the specified current working directory with a name that contains the word route and ends with the suffix .js.

File structure

With the help of globbing we have a loose coupling between the server object and its routes. Just add new route files and they will be included the next time you restart your server.

I like to structure the route files according to their path and naming them with their HTTP-method, like so:

server.js
routes/
    users/
        get-route.js
        patch-route.js
        put-route.js
    articles/
        get-route.js
        patch-route.js
        put-route.js

Example route file routes/users/get-route.js

module.exports = {
    method: 'GET',
    path: '/users',
    config: {
        description: 'Fetch users',
        // ...
    },
    handler: function (request, reply) {
        // ...
    }
};

Final thoughts

Globbing and iterating over files is not a particularly fast process, hence a caching layer may be worth investigating in production builds depending on your circumstances.

Try hapi-auto-route plugin! It's is very simple to use and allow prefix in your route path.

I know this is already approved. I put down my solution in case someone wants a quick fix and new to Hapi.

Also I included some NPM too so Newbees can see how to to use the server.register with multiple plugin in the case ( good + hapi-auto-route )

Installed some npm packages:

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

In your 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!');
        } 
    },
];

Now run: node server.js

Cheers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!