node.js&快递 - 全球模块&应用程序结构的最佳实践

时间:2013-09-13 15:20:30

标签: javascript node.js mongodb express mongoose

我正在为我的mongodb构建一个使用express和mongoose的REST api的node.js应用程序。我现在已经完成了所有设置的CRUD端点,但我只是想知道两件事。

  1. 如何扩展这种路由方式,具体来说,如何在路由之间共享模块。我希望我的每个路由都进入一个新文件,但显然只有一个数据库连接,你可以看到我在people.js的顶部包含了mongoose。

  2. 我必须在我的people.js中写出模型的模式3次吗?第一个模式定义了模型,然后我列出了createPerson和updatePerson函数中的所有变量。这感觉就像我在当天制作php / mysql CRUD一样哈哈。对于更新功能,我尝试编写一个循环来循环播放" p"自动检测要更新的字段,但无济于事。任何提示或建议都会很棒。

  3. 此外,我喜欢整个应用程序的任何意见,对节点不熟悉,很难知道你做某事的方式是最有效的或最好的&#34 #34;实践。谢谢!

    app.js

    // Node Modules
    var express     = require('express');
        app         = express();
        app.port    = 3000;
    
    
    
    // Routes
    var people      = require('./routes/people');
    
    /*
    var locations   = require('./routes/locations');
    var menus       = require('./routes/menus');
    var products    = require('./routes/products');
    */
    
    
    // Node Configure
    app.configure(function(){
      app.use(express.bodyParser());
      app.use(app.router);
    });
    
    
    
    // Start the server on port 3000
    app.listen(app.port);
    
    
    
    /*********
    ENDPOINTS 
    *********/
    
    // People
    app.get('/people', people.allPeople); // Return all people
    app.post('/people', people.createPerson); // Create A Person
    app.get('/people/:id', people.personById); // Return person by id
    app.put('/people/:id', people.updatePerson); // Update a person by id
    app.delete('/people/:id', people.deletePerson); // Delete a person by id
    
    console.log('Server started on port ' + app.port);
    

    people.js

    //Database
    var mongoose = require("mongoose");
    mongoose.connect('mongodb://Shans-MacBook-Pro.local/lantern/');
    
    
    // Schema
    var Schema = mongoose.Schema;  
    var Person = new Schema({  
        first_name: String,
        last_name: String,
        address: {
            unit: Number,
            address: String,
            zipcode: String,
            city: String,
            region: String,
            country: String
        },
        image: String, 
        job_title: String,
        created_at: { type: Date, default: Date.now },
        active_until: { type: Date, default: null },
        hourly_wage: Number,
        store_id: Number, // Inheirit store info
        employee_number: Number
    
    });
    var PersonModel = mongoose.model('Person', Person);  
    
    
    // Return all people
    exports.allPeople = function(req, res){
        return PersonModel.find(function (err, person) {
          if (!err) {
            return res.send(person);
          } else {
            return res.send(err);
          }
        });
    }
    
    
    // Create A Person
    exports.createPerson = function(req, res){
        var person = new PersonModel({
            first_name: req.body.first_name,
            last_name: req.body.last_name,
            address: {
                unit: req.body.address.unit,
                address: req.body.address.address,
                zipcode: req.body.address.zipcode,
                city: req.body.address.city,
                region: req.body.address.region,
                country: req.body.address.country
            },
            image: req.body.image,
            job_title: req.body.job_title,
            hourly_wage: req.body.hourly_wage,
            store_id: req.body.location,
            employee_number: req.body.employee_number
        });
    
        person.save(function (err) {
            if (!err) {
                return res.send(person);
            } else {
                console.log(err);
                return res.send(404, { error: "Person was not created." });
            }
        });
    
        return res.send(person);
    }
    
    
    // Return person by id
    exports.personById = function (req, res){
      return PersonModel.findById(req.params.id, function (err, person) {
        if (!err) {
            return res.send(person);
        } else {
            console.log(err);
            return res.send(404, { error: "That person doesn't exist." });
        }
      });
    }
    
    
    // Delete a person by id
    exports.deletePerson = function (req, res){
      return PersonModel.findById(req.params.id, function (err, person) {
        return person.remove(function (err) {
          if (!err) {
              return res.send(person.id + " deleted");
          } else {
              console.log(err);
              return res.send(404, { error: "Person was not deleted." });
          }
        });
      });
    }
    
    
    
    // Update a person by id
    exports.updatePerson = function(req, res){
        return PersonModel.findById(req.params.id, function(err, p){        
            if(!p){
                return res.send(err)
            } else {
                p.first_name = req.body.first_name;
                p.last_name = req.body.last_name;
                p.address.unit = req.body.address.unit;
                p.address.address = req.body.address.address;
                p.address.zipcode = req.body.address.zipcode;
                p.address.city = req.body.address.city;
                p.address.region = req.body.address.region;
                p.address.country = req.body.address.country;
                p.image = req.body.image;
                p.job_title = req.body.job_title;
                p.hourly_wage = req.body.hourly_wage;
                p.store_id = req.body.location;
                p.employee_number = req.body.employee_number;
    
                p.save(function(err){
                    if(!err){
                        return res.send(p);
                    } else {
                        console.log(err);
                        return res.send(404, { error: "Person was not updated." });
                    }
                });
            }
        });
    }
    

3 个答案:

答案 0 :(得分:20)

我在这里采取了另一种方法。不是说它是最好的,但让我解释一下。

  1. 每个架构(和模型)都在自己的文件(模块)中
  2. 特定REST资源的每组路由都在自己的文件(模块)中
  3. 每个路由模块只需require所需的Mongoose模型(仅1)
  4. 主文件(应用程序入口点)只是require所有注册它们的路由模块。
  5. Mongo连接位于根文件中,并作为参数传递给任何需要它的地方。
  6. 我的应用根目录下有两个子文件夹 - routesschemas

    这种方法的好处是:

    • 您只需编写一次架构。
    • 您不会使用每个REST资源(CRUD)的4-5个路由的路由注册污染您的主应用程序文件
    • 您只需定义一次数据库连接

    以下是特定模式文件的外观:

    档案:/schemas/theaterSchema.js

    module.exports = function(db) {
            return db.model('Theater', TheaterSchema());
    }
    
    function TheaterSchema () {
            var Schema = require('mongoose').Schema;
    
            return new Schema({
                title: { type: String, required: true },
                description: { type: String, required: true },
                address: { type: String, required: true },
                latitude: { type: Number, required: false },
                longitude: { type: Number, required: false },
                phone: { type: String, required: false }
        });
    }
    

    以下是特定资源的路径集合的外观:

    文件:/routes/theaters.js

    module.exports = function (app, options) {
    
        var mongoose = options.mongoose;
        var Schema = options.mongoose.Schema;
        var db = options.db;
    
        var TheaterModel = require('../schemas/theaterSchema')(db);
    
        app.get('/api/theaters', function (req, res) {
                var qSkip = req.query.skip;
                var qTake = req.query.take;
                var qSort = req.query.sort;
                var qFilter = req.query.filter;
                return TheaterModel.find().sort(qSort).skip(qSkip).limit(qTake)
                .exec(function (err, theaters) {
                        // more code
                });
        });
    
        app.post('/api/theaters', function (req, res) {
          var theater;
    
          theater.save(function (err) {
            // more code
          });
          return res.send(theater);
        });
    
        app.get('/api/theaters/:id', function (req, res) {
          return TheaterModel.findById(req.params.id, function (err, theater) {
            // more code
          });
        });
    
        app.put('/api/theaters/:id', function (req, res) {
          return TheaterModel.findById(req.params.id, function (err, theater) {
            // more code
          });
        });
    
        app.delete('/api/theaters/:id', function (req, res) {
          return TheaterModel.findById(req.params.id, function (err, theater) {
            return theater.remove(function (err) {
              // more code
            });
          });
        });
    };
    

    这是根应用程序文件,它初始化连接并注册所有路由:

    文件:app.js

    var application_root = __dirname,
            express = require('express'),
            path = require('path'),
            mongoose = require('mongoose'),
            http = require('http');
    
    var app = express();
    
    var dbProduction = mongoose.createConnection('mongodb://here_insert_the_mongo_connection_string');
    
    app.configure(function () {
            app.use(express.bodyParser());
            app.use(express.methodOverride());
            app.use(app.router);
            app.use(express.static(path.join(application_root, "public")));
            app.use('/images/tmb', express.static(path.join(application_root, "images/tmb")));
            app.use('/images/plays', express.static(path.join(application_root, "images/plays")));
            app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
    });
    
    app.get('/api', function (req, res) {
            res.send('API is running');
    });
    
    var theatersApi = require('./routes/theaters')(app, { 'mongoose': mongoose, 'db': dbProduction });
    // more code
    
    app.listen(4242);
    

    希望这有用。

答案 1 :(得分:4)

我发现这个StackOverflow帖子非常有帮助:

File Structure of Mongoose & NodeJS Project

诀窍是将您的架构放入models目录。然后,在任何路线中,您都可以require('../models').whatever

另外,我通常在app.js中启动mongoose db连接,并且只在连接启动后启动Express服务器:

mongoose.connect('mongodb://localhost/whateverdb')
mongoose.connection.on('error', function(err) {
  console.log("Error while connecting to MongoDB:  " + err);
  process.exit();
});
mongoose.connection.on('connected', function(err) {
  console.log('mongoose is now connected');
  // start app here
  http.createServer(app).listen(app.get('port'), function(){
    console.log('Express server listening on port ' + app.get('port'));
  });

});

答案 2 :(得分:3)

我会看看这个项目https://github.com/madhums/node-express-mongoose-demo。这是一个关于如何以标准方式构建nodejs应用程序的一个很好的例子。